summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/Notification.java2
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java19
-rw-r--r--core/java/android/hardware/input/InputManager.java2
-rw-r--r--core/java/android/os/BinderProxy.java4
-rw-r--r--core/java/android/os/storage/StorageManager.java11
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/service/dreams/DreamOverlayService.java16
-rw-r--r--core/java/android/service/dreams/DreamService.java30
-rw-r--r--core/java/android/service/dreams/IDreamOverlay.aidl3
-rw-r--r--core/java/android/view/ViewRootImpl.java3
-rw-r--r--core/java/android/view/WindowManager.java14
-rw-r--r--core/java/com/android/internal/util/ObservableServiceConnection.java7
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java297
-rw-r--r--core/java/com/android/internal/util/ScreenshotRequest.aidl19
-rw-r--r--core/java/com/android/internal/util/ScreenshotRequest.java332
-rw-r--r--core/java/com/android/internal/view/RotationPolicy.java9
-rw-r--r--core/res/res/values-eu/strings.xml2
-rw-r--r--core/res/res/values-ky/strings.xml12
-rw-r--r--core/res/res/values-pt-rBR/strings.xml2
-rw-r--r--core/res/res/values-pt/strings.xml2
-rw-r--r--core/res/res/values-vi/strings.xml22
-rw-r--r--core/res/res/values/colors_material.xml4
-rw-r--r--core/res/res/values/config.xml15
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java16
-rw-r--r--core/tests/screenshothelpertests/Android.bp3
-rw-r--r--core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java41
-rw-r--r--core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotRequestTest.java139
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java14
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt7
-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/desktopmode/IDesktopMode.aidl3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java24
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java9
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java35
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt30
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt23
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java33
-rw-r--r--packages/PackageInstaller/res/values-ky/strings.xml2
-rw-r--r--packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java294
-rw-r--r--packages/SystemUI/AndroidManifest.xml16
-rw-r--r--packages/SystemUI/README.md90
-rw-r--r--packages/SystemUI/TEST_MAPPING21
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt7
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt10
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt106
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt24
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt147
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt245
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt2
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetector.kt150
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt16
-rw-r--r--packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt296
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt3
-rw-r--r--packages/SystemUI/docs/dagger.md186
-rw-r--r--packages/SystemUI/ktfmt_includes.txt7
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt118
-rw-r--r--packages/SystemUI/plugin/Android.bp1
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt24
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java5
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt16
-rw-r--r--packages/SystemUI/res-product/values-de/strings.xml4
-rw-r--r--packages/SystemUI/res-product/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res-product/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res-product/values-pt-rBR/strings.xml4
-rw-r--r--packages/SystemUI/res-product/values-pt/strings.xml4
-rw-r--r--packages/SystemUI/res-product/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/res/drawable/ic_camera.xml10
-rw-r--r--packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml31
-rw-r--r--packages/SystemUI/res/drawable/ic_note_task_shortcut_widget.xml (renamed from packages/SystemUI/res/drawable/ic_note_task_button.xml)5
-rw-r--r--packages/SystemUI/res/drawable/ic_videocam.xml10
-rw-r--r--packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml58
-rw-r--r--packages/SystemUI/res/drawable/keyguard_bottom_affordance_selected_border.xml31
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml2
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml1
-rw-r--r--packages/SystemUI/res/layout/media_ttt_chip_receiver.xml9
-rw-r--r--packages/SystemUI/res/layout/ongoing_privacy_chip.xml1
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_footer.xml11
-rw-r--r--packages/SystemUI/res/values-af/strings.xml19
-rw-r--r--packages/SystemUI/res/values-am/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml19
-rw-r--r--packages/SystemUI/res/values-as/strings.xml17
-rw-r--r--packages/SystemUI/res/values-az/strings.xml17
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml17
-rw-r--r--packages/SystemUI/res/values-be/strings.xml17
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml21
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml15
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml23
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml17
-rw-r--r--packages/SystemUI/res/values-da/strings.xml19
-rw-r--r--packages/SystemUI/res/values-de/strings.xml33
-rw-r--r--packages/SystemUI/res/values-el/strings.xml15
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml10
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml9
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml10
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml10
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml9
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml19
-rw-r--r--packages/SystemUI/res/values-es/strings.xml19
-rw-r--r--packages/SystemUI/res/values-et/strings.xml19
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml19
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml17
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml17
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml17
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml21
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml17
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml21
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml17
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml19
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml17
-rw-r--r--packages/SystemUI/res/values-in/strings.xml17
-rw-r--r--packages/SystemUI/res/values-is/strings.xml17
-rw-r--r--packages/SystemUI/res/values-it/strings.xml19
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml25
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml21
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml17
-rw-r--r--packages/SystemUI/res/values-km/strings.xml19
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml33
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml17
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml15
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml17
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml15
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml15
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml17
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml17
-rw-r--r--packages/SystemUI/res/values-my/strings.xml17
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml17
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-or/strings.xml21
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml17
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml17
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml13
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml17
-rw-r--r--packages/SystemUI/res/values-si/strings.xml17
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml23
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml17
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml15
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml1
-rw-r--r--packages/SystemUI/res/values-sw600dp/config.xml11
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml4
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml17
-rw-r--r--packages/SystemUI/res/values-te/strings.xml15
-rw-r--r--packages/SystemUI/res/values-th/strings.xml17
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml15
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml19
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml14
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml17
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml21
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml21
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml19
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml17
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/res/values/strings.xml25
-rw-r--r--packages/SystemUI/res/xml/large_screen_shade_header.xml95
-rw-r--r--packages/SystemUI/shared/Android.bp3
-rw-r--r--packages/SystemUI/shared/proguard_flags.flags1
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputDevice.kt39
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputManager.kt69
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java43
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java13
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java17
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt105
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt99
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java (renamed from packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaColorSchemes.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt130
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverRippleController.kt163
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceModule.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java319
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt214
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsModule.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt111
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt)32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt173
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt81
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt115
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt344
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt115
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt163
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt190
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt101
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt174
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt60
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java131
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt84
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt143
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt103
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt144
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt327
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt198
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt90
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt171
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakReporterTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt243
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java7
-rw-r--r--services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java2
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java23
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java11
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java24
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java24
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java47
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java1
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java6
-rw-r--r--services/core/java/com/android/server/wm/LetterboxConfiguration.java34
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java17
-rw-r--r--services/core/java/com/android/server/wm/Task.java7
-rw-r--r--services/core/java/com/android/server/wm/TrustedOverlayHost.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java18
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java13
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java77
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java75
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java126
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java8
459 files changed, 11057 insertions, 3253 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 93c0c4d7a024..8c00c6a4bfd8 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2411,6 +2411,7 @@ package android.service.dreams {
public abstract class DreamOverlayService extends android.app.Service {
ctor public DreamOverlayService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+ method public void onEndDream();
method public abstract void onStartDream(@NonNull android.view.WindowManager.LayoutParams);
method public final void requestExit();
method public final boolean shouldShowComplications();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8b41aa4a7e7d..46d8481646c9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7944,8 +7944,6 @@ public class Notification implements Parcelable
* @hide
*/
public MessagingStyle setShortcutIcon(@Nullable Icon conversationIcon) {
- // TODO(b/228941516): This icon should be downscaled to avoid using too much memory,
- // see reduceImageSizes.
mShortcutIcon = conversationIcon;
return this;
}
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index a51b9d3956df..27f9f54d9522 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -1406,6 +1406,17 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
+ * Return the number of entries in the cache. This is used for testing and has package-only
+ * visibility.
+ * @hide
+ */
+ public int size() {
+ synchronized (mLock) {
+ return mCache.size();
+ }
+ }
+
+ /**
* Returns a list of caches alive at the current time.
*/
@GuardedBy("sGlobalLock")
@@ -1612,8 +1623,12 @@ public class PropertyInvalidatedCache<Query, Result> {
* @hide
*/
public static void onTrimMemory() {
- for (PropertyInvalidatedCache pic : getActiveCaches()) {
- pic.clear();
+ ArrayList<PropertyInvalidatedCache> activeCaches;
+ synchronized (sGlobalLock) {
+ activeCaches = getActiveCaches();
+ }
+ for (int i = 0; i < activeCaches.size(); i++) {
+ activeCaches.get(i).clear();
}
}
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index baf8836c5af5..b6cd06ea8b5c 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -168,7 +168,7 @@ public final class InputManager {
* The <code>android:label</code> attribute specifies a human-readable descriptive
* label to describe the keyboard layout in the user interface, such as "English (US)".
* The <code>android:keyboardLayout</code> attribute refers to a
- * <a href="http://source.android.com/tech/input/key-character-map-files.html">
+ * <a href="https://source.android.com/docs/core/interaction/input/key-character-map-files">
* key character map</a> resource that defines the keyboard layout.
* </p>
*/
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 63306612fdaf..1929a4d562d4 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -536,8 +536,8 @@ public final class BinderProxy implements IBinder {
mWarnOnBlocking = false;
warnOnBlocking = false;
- if (Build.IS_USERDEBUG) {
- // Log this as a WTF on userdebug builds.
+ if (Build.IS_USERDEBUG || Build.IS_ENG) {
+ // Log this as a WTF on userdebug and eng builds.
Log.wtf(Binder.TAG,
"Outgoing transactions from this process must be FLAG_ONEWAY",
new Throwable());
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 497bfa6380bc..d9604b3f0145 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -2555,6 +2555,8 @@ public class StorageManager {
* This API doesn't require any special permissions, though typical implementations
* will require being called from an SELinux domain that allows setting file attributes
* related to quota (eg the GID or project ID).
+ * If the calling user has MANAGE_EXTERNAL_STORAGE permissions, quota for shared profile's
+ * volumes is also updated.
*
* The default platform user of this API is the MediaProvider process, which is
* responsible for managing all of external storage.
@@ -2575,7 +2577,14 @@ public class StorageManager {
@QuotaType int quotaType) throws IOException {
long projectId;
final String filePath = path.getCanonicalPath();
- final StorageVolume volume = getStorageVolume(path);
+ int volFlags = FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE;
+ // If caller has MANAGE_EXTERNAL_STORAGE permission, results from User Profile(s) are also
+ // returned by enabling FLAG_INCLUDE_SHARED_PROFILE.
+ if (mContext.checkSelfPermission(MANAGE_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
+ volFlags |= FLAG_INCLUDE_SHARED_PROFILE;
+ }
+ final StorageVolume[] availableVolumes = getVolumeList(mContext.getUserId(), volFlags);
+ final StorageVolume volume = getStorageVolume(availableVolumes, path);
if (volume == null) {
Log.w(TAG, "Failed to update quota type for " + filePath);
return;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a1a1c45cdb6f..ce4a7357cc4f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9534,7 +9534,7 @@ public final class Settings {
/**
* Indicates whether "seen" notifications should be suppressed from the lockscreen.
* <p>
- * Type: int (0 for false, 1 for true)
+ * Type: int (0 for unset, 1 for true, 2 for false)
*
* @hide
*/
@@ -9838,9 +9838,11 @@ public final class Settings {
/**
* Whether or not a SFPS device is enabling the performant auth setting.
+ * The "_V2" suffix was added to re-introduce the default behavior for
+ * users. See b/265264294 fore more details.
* @hide
*/
- public static final String SFPS_PERFORMANT_AUTH_ENABLED = "sfps_performant_auth_enabled";
+ public static final String SFPS_PERFORMANT_AUTH_ENABLED = "sfps_performant_auth_enabled_v2";
/**
* Whether or not debugging is enabled.
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 6e8198ba0cd1..bf5b970311d0 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -51,6 +51,11 @@ public abstract class DreamOverlayService extends Service {
}
@Override
+ public void endDream() {
+ onEndDream();
+ }
+
+ @Override
public void wakeUp() {
onWakeUp(() -> {
try {
@@ -83,13 +88,22 @@ public abstract class DreamOverlayService extends Service {
/**
* This method is overridden by implementations to handle when the dream has been requested
- * to wakeup. This allows any overlay animations to run.
+ * to wakeup. This allows any overlay animations to run. By default, the method will invoke
+ * the callback immediately.
*
* @param onCompleteCallback The callback to trigger to notify the dream service that the
* overlay has completed waking up.
* @hide
*/
public void onWakeUp(@NonNull Runnable onCompleteCallback) {
+ onCompleteCallback.run();
+ }
+
+ /**
+ * This method is overridden by implementations to handle when the dream has ended. There may
+ * be earlier signals leading up to this step, such as @{@link #onWakeUp(Runnable)}.
+ */
+ public void onEndDream() {
}
/**
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 8b9852a8f1b7..d3788862b6c0 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -297,14 +297,20 @@ public class DreamService extends Service implements Window.Callback {
}
public void addConsumer(Consumer<IDreamOverlay> consumer) {
- mConsumers.add(consumer);
- if (mOverlay != null) {
- consumer.accept(mOverlay);
- }
+ execute(() -> {
+ mConsumers.add(consumer);
+ if (mOverlay != null) {
+ consumer.accept(mOverlay);
+ }
+ });
}
public void removeConsumer(Consumer<IDreamOverlay> consumer) {
- mConsumers.remove(consumer);
+ execute(() -> mConsumers.remove(consumer));
+ }
+
+ public void clearConsumers() {
+ execute(() -> mConsumers.clear());
}
}
@@ -1383,6 +1389,17 @@ public class DreamService extends Service implements Window.Callback {
@Override
public void onViewDetachedFromWindow(View v) {
+ if (mOverlayConnection != null) {
+ mOverlayConnection.addConsumer(overlay -> {
+ try {
+ overlay.endDream();
+ } catch (RemoteException e) {
+ Log.e(mTag, "could not inform overlay of dream end:" + e);
+ }
+ });
+ mOverlayConnection.clearConsumers();
+ }
+
if (mActivity == null || !mActivity.isChangingConfigurations()) {
// Only stop the dream if the view is not detached by relaunching
// activity for configuration changes. It is important to also clear
@@ -1391,9 +1408,6 @@ public class DreamService extends Service implements Window.Callback {
mActivity = null;
finish();
}
- if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) {
- mOverlayConnection.removeConsumer(mDreamStartOverlayConsumer);
- }
}
});
}
diff --git a/core/java/android/service/dreams/IDreamOverlay.aidl b/core/java/android/service/dreams/IDreamOverlay.aidl
index 7aeceb2ce538..0e4bd3bd547b 100644
--- a/core/java/android/service/dreams/IDreamOverlay.aidl
+++ b/core/java/android/service/dreams/IDreamOverlay.aidl
@@ -41,4 +41,7 @@ interface IDreamOverlay {
/** Called when the dream is waking, to do any exit animations */
void wakeUp();
+
+ /** Called when the dream has ended. */
+ void endDream();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1834d19a8e67..43bbcfb1e94a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -73,6 +73,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CO
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -2766,7 +2767,7 @@ public final class ViewRootImpl implements ViewParent,
* TODO(b/260382739): Apply this to all windows.
*/
private static boolean shouldOptimizeMeasure(final WindowManager.LayoutParams lp) {
- return lp.type == TYPE_NOTIFICATION_SHADE;
+ return (lp.privateFlags & PRIVATE_FLAG_OPTIMIZE_MEASURE) != 0;
}
private Rect getWindowBoundsInsetSystemBars() {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index abc49266bb19..a37c24499aff 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2580,6 +2580,15 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100;
/**
+ * Flag to indicate that the view hierarchy of the window can only be measured when
+ * necessary. If a window size can be known by the LayoutParams, we can use the size to
+ * relayout window, and we don't have to measure the view hierarchy before laying out the
+ * views. This reduces the chances to perform measure.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_OPTIMIZE_MEASURE = 0x00000200;
+
+ /**
* Flag that prevents the wallpaper behind the current window from receiving touch events.
*
* {@hide}
@@ -2781,6 +2790,7 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_NO_MOVE_ANIMATION,
PRIVATE_FLAG_COMPATIBLE_WINDOW,
PRIVATE_FLAG_SYSTEM_ERROR,
+ PRIVATE_FLAG_OPTIMIZE_MEASURE,
PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
@@ -2841,6 +2851,10 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_SYSTEM_ERROR,
name = "SYSTEM_ERROR"),
@ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_OPTIMIZE_MEASURE,
+ equals = PRIVATE_FLAG_OPTIMIZE_MEASURE,
+ name = "OPTIMIZE_MEASURE"),
+ @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
equals = PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
name = "DISABLE_WALLPAPER_TOUCH_EVENTS"),
diff --git a/core/java/com/android/internal/util/ObservableServiceConnection.java b/core/java/com/android/internal/util/ObservableServiceConnection.java
index 3165d293bd91..45256fd26cba 100644
--- a/core/java/com/android/internal/util/ObservableServiceConnection.java
+++ b/core/java/com/android/internal/util/ObservableServiceConnection.java
@@ -165,6 +165,13 @@ public class ObservableServiceConnection<T> implements ServiceConnection {
}
/**
+ * Executes code on the executor specified at construction.
+ */
+ public void execute(Runnable runnable) {
+ mExecutor.execute(runnable);
+ }
+
+ /**
* Initiate binding to the service.
*
* @return {@code true} if initiating binding succeed, {@code false} if the binding failed or
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index 79c519645a24..3a393b689717 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -1,7 +1,7 @@
package com.android.internal.util;
import static android.content.Intent.ACTION_USER_SWITCHED;
-import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE;
+import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -11,29 +11,18 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.graphics.Bitmap;
-import android.graphics.ColorSpace;
-import android.graphics.Insets;
-import android.graphics.ParcelableColorSpace;
-import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
import android.net.Uri;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.view.WindowManager.ScreenshotSource;
-import android.view.WindowManager.ScreenshotType;
import com.android.internal.annotations.VisibleForTesting;
-import java.util.Objects;
import java.util.function.Consumer;
public class ScreenshotHelper {
@@ -41,212 +30,6 @@ public class ScreenshotHelper {
public static final int SCREENSHOT_MSG_URI = 1;
public static final int SCREENSHOT_MSG_PROCESS_COMPLETE = 2;
- /**
- * Describes a screenshot request.
- */
- public static class ScreenshotRequest implements Parcelable {
- @ScreenshotType
- private final int mType;
-
- @ScreenshotSource
- private final int mSource;
-
- private final Bundle mBitmapBundle;
- private final Rect mBoundsInScreen;
- private final Insets mInsets;
- private final int mTaskId;
- private final int mUserId;
- private final ComponentName mTopComponent;
-
-
- public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source) {
- this(type, source, /* topComponent */ null);
- }
-
- public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source,
- ComponentName topComponent) {
- this(type,
- source,
- /* bitmapBundle*/ null,
- /* boundsInScreen */ null,
- /* insets */ null,
- /* taskId */ -1,
- /* userId */ -1,
- topComponent);
- }
-
- public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source,
- Bundle bitmapBundle, Rect boundsInScreen, Insets insets, int taskId, int userId,
- ComponentName topComponent) {
- mType = type;
- mSource = source;
- mBitmapBundle = bitmapBundle;
- mBoundsInScreen = boundsInScreen;
- mInsets = insets;
- mTaskId = taskId;
- mUserId = userId;
- mTopComponent = topComponent;
- }
-
- ScreenshotRequest(Parcel in) {
- mType = in.readInt();
- mSource = in.readInt();
- if (in.readInt() == 1) {
- mBitmapBundle = in.readBundle(getClass().getClassLoader());
- mBoundsInScreen = in.readParcelable(Rect.class.getClassLoader(), Rect.class);
- mInsets = in.readParcelable(Insets.class.getClassLoader(), Insets.class);
- mTaskId = in.readInt();
- mUserId = in.readInt();
- mTopComponent = in.readParcelable(ComponentName.class.getClassLoader(),
- ComponentName.class);
- } else {
- mBitmapBundle = null;
- mBoundsInScreen = null;
- mInsets = null;
- mTaskId = -1;
- mUserId = -1;
- mTopComponent = null;
- }
- }
-
- @ScreenshotType
- public int getType() {
- return mType;
- }
-
- @ScreenshotSource
- public int getSource() {
- return mSource;
- }
-
- public Bundle getBitmapBundle() {
- return mBitmapBundle;
- }
-
- public Rect getBoundsInScreen() {
- return mBoundsInScreen;
- }
-
- public Insets getInsets() {
- return mInsets;
- }
-
- public int getTaskId() {
- return mTaskId;
- }
-
- public int getUserId() {
- return mUserId;
- }
-
- public ComponentName getTopComponent() {
- return mTopComponent;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mType);
- dest.writeInt(mSource);
- if (mBitmapBundle == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(1);
- dest.writeBundle(mBitmapBundle);
- dest.writeParcelable(mBoundsInScreen, 0);
- dest.writeParcelable(mInsets, 0);
- dest.writeInt(mTaskId);
- dest.writeInt(mUserId);
- dest.writeParcelable(mTopComponent, 0);
- }
- }
-
- @NonNull
- public static final Parcelable.Creator<ScreenshotRequest> CREATOR =
- new Parcelable.Creator<ScreenshotRequest>() {
-
- @Override
- public ScreenshotRequest createFromParcel(Parcel source) {
- return new ScreenshotRequest(source);
- }
-
- @Override
- public ScreenshotRequest[] newArray(int size) {
- return new ScreenshotRequest[size];
- }
- };
- }
-
- /**
- * Bundler used to convert between a hardware bitmap and a bundle without copying the internal
- * content. This is expected to be used together with {@link #provideScreenshot} to handle a
- * hardware bitmap as a screenshot.
- */
- public static final class HardwareBitmapBundler {
- private static final String KEY_BUFFER = "bitmap_util_buffer";
- private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
-
- private HardwareBitmapBundler() {
- }
-
- /**
- * Creates a Bundle that represents the given Bitmap.
- * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
- * copies when passing across processes, only pass to processes you trust.
- *
- * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
- * returned Bundle should be treated as a standalone object.
- *
- * @param bitmap to convert to bundle
- * @return a Bundle representing the bitmap, should only be parsed by
- * {@link #bundleToHardwareBitmap(Bundle)}
- */
- public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
- if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
- throw new IllegalArgumentException(
- "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
- }
-
- // Bitmap assumes SRGB for null color space
- ParcelableColorSpace colorSpace =
- bitmap.getColorSpace() == null
- ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
- : new ParcelableColorSpace(bitmap.getColorSpace());
-
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
- bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
-
- return bundle;
- }
-
- /**
- * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
- *
- * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing
- * this Bitmap on to any other source.
- *
- * @param bundle containing the bitmap
- * @return a hardware Bitmap
- */
- public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
- if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
- throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
- }
-
- HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER, HardwareBuffer.class);
- ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE,
- ParcelableColorSpace.class);
-
- return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
- colorSpace.getColorSpace());
- }
- }
-
private static final String TAG = "ScreenshotHelper";
// Time until we give up on the screenshot & show an error instead.
@@ -277,68 +60,53 @@ public class ScreenshotHelper {
/**
* Request a screenshot be taken.
* <p>
- * Added to support reducing unit test duration; the method variant without a timeout argument
- * is recommended for general use.
+ * Convenience method for taking a full screenshot with provided source.
*
- * @param type The type of screenshot, defined by {@link ScreenshotType}
- * @param source The source of the screenshot request, defined by {@link ScreenshotSource}
- * @param handler used to process messages received from the screenshot service
+ * @param source source of the screenshot request, defined by {@link
+ * ScreenshotSource}
+ * @param handler used to process messages received from the screenshot service
* @param completionConsumer receives the URI of the captured screenshot, once saved or
- * null if no screenshot was saved
+ * null if no screenshot was saved
*/
- public void takeScreenshot(@ScreenshotType int type, @ScreenshotSource int source,
- @NonNull Handler handler, @Nullable Consumer<Uri> completionConsumer) {
- ScreenshotRequest screenshotRequest = new ScreenshotRequest(type, source);
- takeScreenshot(handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS,
- completionConsumer);
+ public void takeScreenshot(@ScreenshotSource int source, @NonNull Handler handler,
+ @Nullable Consumer<Uri> completionConsumer) {
+ ScreenshotRequest request =
+ new ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, source).build();
+ takeScreenshot(request, handler, completionConsumer);
}
/**
* Request a screenshot be taken.
* <p>
- * Added to support reducing unit test duration; the method variant without a timeout argument
- * is recommended for general use.
*
- * @param type The type of screenshot, defined by {@link ScreenshotType}
- * @param source The source of the screenshot request, defined by {@link ScreenshotSource}
- * @param handler used to process messages received from the screenshot service
- * @param timeoutMs time limit for processing, intended only for testing
+ * @param request description of the screenshot request, either for taking a
+ * screenshot or
+ * providing a bitmap
+ * @param handler used to process messages received from the screenshot service
* @param completionConsumer receives the URI of the captured screenshot, once saved or
- * null if no screenshot was saved
+ * null if no screenshot was saved
*/
- @VisibleForTesting
- public void takeScreenshot(@ScreenshotType int type, @ScreenshotSource int source,
- @NonNull Handler handler, long timeoutMs, @Nullable Consumer<Uri> completionConsumer) {
- ScreenshotRequest screenshotRequest = new ScreenshotRequest(type, source);
- takeScreenshot(handler, screenshotRequest, timeoutMs, completionConsumer);
+ public void takeScreenshot(ScreenshotRequest request, @NonNull Handler handler,
+ @Nullable Consumer<Uri> completionConsumer) {
+ takeScreenshotInternal(request, handler, completionConsumer, SCREENSHOT_TIMEOUT_MS);
}
/**
- * Request that provided image be handled as if it was a screenshot.
+ * Request a screenshot be taken.
+ * <p>
+ * Added to support reducing unit test duration; the method variant without a timeout argument
+ * is recommended for general use.
*
- * @param screenshotBundle Bundle containing the buffer and color space of the screenshot.
- * @param boundsInScreen The bounds in screen coordinates that the bitmap originated from.
- * @param insets The insets that the image was shown with, inside the screen bounds.
- * @param taskId The taskId of the task that the screen shot was taken of.
- * @param userId The userId of user running the task provided in taskId.
- * @param topComponent The component name of the top component running in the task.
- * @param source The source of the screenshot request, defined by {@link ScreenshotSource}
- * @param handler A handler used in case the screenshot times out
+ * @param request description of the screenshot request, either for taking a
+ * screenshot or providing a bitmap
+ * @param handler used to process messages received from the screenshot service
+ * @param timeoutMs time limit for processing, intended only for testing
* @param completionConsumer receives the URI of the captured screenshot, once saved or
- * null if no screenshot was saved
+ * null if no screenshot was saved
*/
- public void provideScreenshot(@NonNull Bundle screenshotBundle, @NonNull Rect boundsInScreen,
- @NonNull Insets insets, int taskId, int userId, ComponentName topComponent,
- @ScreenshotSource int source, @NonNull Handler handler,
- @Nullable Consumer<Uri> completionConsumer) {
- ScreenshotRequest screenshotRequest = new ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE,
- source, screenshotBundle, boundsInScreen, insets, taskId, userId, topComponent);
- takeScreenshot(handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS, completionConsumer);
- }
-
- private void takeScreenshot(@NonNull Handler handler,
- ScreenshotRequest screenshotRequest, long timeoutMs,
- @Nullable Consumer<Uri> completionConsumer) {
+ @VisibleForTesting
+ public void takeScreenshotInternal(ScreenshotRequest request, @NonNull Handler handler,
+ @Nullable Consumer<Uri> completionConsumer, long timeoutMs) {
synchronized (mScreenshotLock) {
final Runnable mScreenshotTimeout = () -> {
@@ -354,7 +122,7 @@ public class ScreenshotHelper {
}
};
- Message msg = Message.obtain(null, 0, screenshotRequest);
+ Message msg = Message.obtain(null, 0, request);
Handler h = new Handler(handler.getLooper()) {
@Override
@@ -471,5 +239,4 @@ public class ScreenshotHelper {
Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT);
}
-
}
diff --git a/core/java/com/android/internal/util/ScreenshotRequest.aidl b/core/java/com/android/internal/util/ScreenshotRequest.aidl
new file mode 100644
index 000000000000..b08905dd0c9a
--- /dev/null
+++ b/core/java/com/android/internal/util/ScreenshotRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.util;
+
+parcelable ScreenshotRequest; \ No newline at end of file
diff --git a/core/java/com/android/internal/util/ScreenshotRequest.java b/core/java/com/android/internal/util/ScreenshotRequest.java
new file mode 100644
index 000000000000..1902f80bd384
--- /dev/null
+++ b/core/java/com/android/internal/util/ScreenshotRequest.java
@@ -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.util;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.os.UserHandle.USER_NULL;
+import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.Insets;
+import android.graphics.ParcelableColorSpace;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.util.Objects;
+
+/**
+ * Describes a screenshot request.
+ */
+public class ScreenshotRequest implements Parcelable {
+ private static final String TAG = "ScreenshotRequest";
+
+ @WindowManager.ScreenshotType
+ private final int mType;
+ @WindowManager.ScreenshotSource
+ private final int mSource;
+ private final ComponentName mTopComponent;
+ private final int mTaskId;
+ private final int mUserId;
+ private final Bitmap mBitmap;
+ private final Rect mBoundsInScreen;
+ private final Insets mInsets;
+
+ private ScreenshotRequest(
+ @WindowManager.ScreenshotType int type, @WindowManager.ScreenshotSource int source,
+ ComponentName topComponent, int taskId, int userId,
+ Bitmap bitmap, Rect boundsInScreen, Insets insets) {
+ mType = type;
+ mSource = source;
+ mTopComponent = topComponent;
+ mTaskId = taskId;
+ mUserId = userId;
+ mBitmap = bitmap;
+ mBoundsInScreen = boundsInScreen;
+ mInsets = insets;
+ }
+
+ ScreenshotRequest(Parcel in) {
+ mType = in.readInt();
+ mSource = in.readInt();
+ mTopComponent = in.readTypedObject(ComponentName.CREATOR);
+ mTaskId = in.readInt();
+ mUserId = in.readInt();
+ mBitmap = HardwareBitmapBundler.bundleToHardwareBitmap(in.readTypedObject(Bundle.CREATOR));
+ mBoundsInScreen = in.readTypedObject(Rect.CREATOR);
+ mInsets = in.readTypedObject(Insets.CREATOR);
+ }
+
+ @WindowManager.ScreenshotType
+ public int getType() {
+ return mType;
+ }
+
+ @WindowManager.ScreenshotSource
+ public int getSource() {
+ return mSource;
+ }
+
+ public Bitmap getBitmap() {
+ return mBitmap;
+ }
+
+ public Rect getBoundsInScreen() {
+ return mBoundsInScreen;
+ }
+
+ public Insets getInsets() {
+ return mInsets;
+ }
+
+ public int getTaskId() {
+ return mTaskId;
+ }
+
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public ComponentName getTopComponent() {
+ return mTopComponent;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mType);
+ dest.writeInt(mSource);
+ dest.writeTypedObject(mTopComponent, 0);
+ dest.writeInt(mTaskId);
+ dest.writeInt(mUserId);
+ dest.writeTypedObject(HardwareBitmapBundler.hardwareBitmapToBundle(mBitmap), 0);
+ dest.writeTypedObject(mBoundsInScreen, 0);
+ dest.writeTypedObject(mInsets, 0);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<ScreenshotRequest> CREATOR =
+ new Parcelable.Creator<ScreenshotRequest>() {
+
+ @Override
+ public ScreenshotRequest createFromParcel(Parcel source) {
+ return new ScreenshotRequest(source);
+ }
+
+ @Override
+ public ScreenshotRequest[] newArray(int size) {
+ return new ScreenshotRequest[size];
+ }
+ };
+
+ /**
+ * Builder class for {@link ScreenshotRequest} objects.
+ */
+ public static class Builder {
+ @WindowManager.ScreenshotType
+ private final int mType;
+
+ @WindowManager.ScreenshotSource
+ private final int mSource;
+
+ private Bitmap mBitmap;
+ private Rect mBoundsInScreen;
+ private Insets mInsets = Insets.NONE;
+ private int mTaskId = INVALID_TASK_ID;
+ private int mUserId = USER_NULL;
+ private ComponentName mTopComponent;
+
+ /**
+ * Begin building a ScreenshotRequest.
+ *
+ * @param type The type of the screenshot request, defined by {@link
+ * WindowManager.ScreenshotType}
+ * @param source The source of the screenshot request, defined by {@link
+ * WindowManager.ScreenshotSource}
+ */
+ public Builder(
+ @WindowManager.ScreenshotType int type,
+ @WindowManager.ScreenshotSource int source) {
+ mType = type;
+ mSource = source;
+ }
+
+ /**
+ * Construct a new {@link ScreenshotRequest} with the set parameters.
+ */
+ public ScreenshotRequest build() {
+ if (mType == TAKE_SCREENSHOT_FULLSCREEN && mBitmap != null) {
+ Log.w(TAG, "Bitmap provided, but request is fullscreen. Bitmap will be ignored.");
+ }
+ if (mType == TAKE_SCREENSHOT_PROVIDED_IMAGE && mBitmap == null) {
+ throw new IllegalStateException(
+ "Request is PROVIDED_IMAGE, but no bitmap is provided!");
+ }
+
+ return new ScreenshotRequest(mType, mSource, mTopComponent, mTaskId, mUserId, mBitmap,
+ mBoundsInScreen, mInsets);
+ }
+
+ /**
+ * Set the top component associated with this request.
+ *
+ * @param topComponent The component name of the top component running in the task.
+ */
+ public Builder setTopComponent(ComponentName topComponent) {
+ mTopComponent = topComponent;
+ return this;
+ }
+
+ /**
+ * Set the task id associated with this request.
+ *
+ * @param taskId The taskId of the task that the screenshot was taken of.
+ */
+ public Builder setTaskId(int taskId) {
+ mTaskId = taskId;
+ return this;
+ }
+
+ /**
+ * Set the user id associated with this request.
+ *
+ * @param userId The userId of user running the task provided in taskId.
+ */
+ public Builder setUserId(int userId) {
+ mUserId = userId;
+ return this;
+ }
+
+ /**
+ * Set the bitmap associated with this request.
+ *
+ * @param bitmap The provided screenshot.
+ */
+ public Builder setBitmap(Bitmap bitmap) {
+ mBitmap = bitmap;
+ return this;
+ }
+
+ /**
+ * Set the bounds for the provided bitmap.
+ *
+ * @param bounds The bounds in screen coordinates that the bitmap originated from.
+ */
+ public Builder setBoundsOnScreen(Rect bounds) {
+ mBoundsInScreen = bounds;
+ return this;
+ }
+
+ /**
+ * Set the insets for the provided bitmap.
+ *
+ * @param insets The insets that the image was shown with, inside the screen bounds.
+ */
+ public Builder setInsets(@NonNull Insets insets) {
+ mInsets = insets;
+ return this;
+ }
+ }
+
+ /**
+ * Bundler used to convert between a hardware bitmap and a bundle without copying the internal
+ * content. This is used together with a fully-defined ScreenshotRequest to handle a hardware
+ * bitmap as a screenshot.
+ */
+ private static final class HardwareBitmapBundler {
+ private static final String KEY_BUFFER = "bitmap_util_buffer";
+ private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
+
+ private HardwareBitmapBundler() {
+ }
+
+ /**
+ * Creates a Bundle that represents the given Bitmap.
+ * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will
+ * avoid
+ * copies when passing across processes, only pass to processes you trust.
+ *
+ * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions,
+ * the
+ * returned Bundle should be treated as a standalone object.
+ *
+ * @param bitmap to convert to bundle
+ * @return a Bundle representing the bitmap, should only be parsed by
+ * {@link #bundleToHardwareBitmap(Bundle)}
+ */
+ private static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
+ if (bitmap == null) {
+ return null;
+ }
+ if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
+ throw new IllegalArgumentException(
+ "Passed bitmap must have hardware config, found: "
+ + bitmap.getConfig());
+ }
+
+ // Bitmap assumes SRGB for null color space
+ ParcelableColorSpace colorSpace =
+ bitmap.getColorSpace() == null
+ ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
+ : new ParcelableColorSpace(bitmap.getColorSpace());
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
+ bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
+
+ return bundle;
+ }
+
+ /**
+ * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)}.
+ *
+ * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful
+ * passing
+ * this Bitmap on to any other source.
+ *
+ * @param bundle containing the bitmap
+ * @return a hardware Bitmap
+ */
+ private static Bitmap bundleToHardwareBitmap(Bundle bundle) {
+ if (bundle == null) {
+ return null;
+ }
+ if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
+ throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
+ }
+
+ HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER, HardwareBuffer.class);
+ ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE,
+ ParcelableColorSpace.class);
+
+ return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
+ colorSpace.getColorSpace());
+ }
+ }
+}
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 869da1ffcb6e..058c6ec4d13c 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -106,7 +106,9 @@ public final class RotationPolicy {
* Enables or disables rotation lock from the system UI toggle.
*/
public static void setRotationLock(Context context, final boolean enabled) {
- final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION;
+ final int rotation = areAllRotationsAllowed(context)
+ || useCurrentRotationOnRotationLockChange(context) ? CURRENT_ROTATION
+ : NATURAL_ROTATION;
setRotationLockAtAngle(context, enabled, rotation);
}
@@ -139,6 +141,11 @@ public final class RotationPolicy {
return context.getResources().getBoolean(R.bool.config_allowAllRotations);
}
+ private static boolean useCurrentRotationOnRotationLockChange(Context context) {
+ return context.getResources().getBoolean(
+ R.bool.config_useCurrentRotationOnRotationLockChange);
+ }
+
private static void setRotationLock(final boolean enabled, final int rotation) {
AsyncTask.execute(new Runnable() {
@Override
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index e60a96e3a4b7..ce02af221d0f 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -78,7 +78,7 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Deitzailearen identitatea zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenik gabe."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Zerbitzua ez da hornitu."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ezin duzu aldatu deitzailearen identitatearen ezarpena."</string>
- <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ez dago mugikorreko datu-zerbitzurik"</string>
+ <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ez dago mugikorretarako datu-zerbitzurik"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Ezin da egin larrialdi-deirik"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ez dago ahots-deien zerbitzurik"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"Ez dago ahozko zerbitzurik eta ezin da egin larrialdi-deirik"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 3db4e9bded7d..27d932aac8fa 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -264,7 +264,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"Учак режими"</string>
<string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"Учак режими КҮЙҮК"</string>
<string name="global_actions_airplane_mode_off_status" msgid="8522219771500505475">"Учак режими ӨЧҮК"</string>
- <string name="global_action_settings" msgid="4671878836947494217">"Жөндөөлөр"</string>
+ <string name="global_action_settings" msgid="4671878836947494217">"Параметрлер"</string>
<string name="global_action_assist" msgid="2517047220311505805">"Жардам"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"Үн жардамчысы"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Бекем кулпулоо"</string>
@@ -631,7 +631,7 @@
<string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Жүзүңүздүн үлгүсүн өчүрүү үчүн басып, жаңы үлгүнү кошуңуз"</string>
<string name="face_setup_notification_title" msgid="8843461561970741790">"Жүзүнөн таанып ачууну тууралоо"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Телефонуңузду карап туруп эле кулпусун ачып алыңыз"</string>
- <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Жүзүнөн таанып ачуу функциясын колдонуу үчүн Жөндөөлөр &gt; Купуялык бөлүмүнө өтүп, "<b>"Камераны колдонууну"</b>" күйгүзүңүз"</string>
+ <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Жүзүнөн таанып ачуу функциясын колдонуу үчүн Параметрлер &gt; Купуялык бөлүмүнө өтүп, "<b>"Камераны колдонууну"</b>" күйгүзүңүз"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Кулпусун ачуунун көбүрөөк жолдорун жөндөңүз"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Манжа изин кошуу үчүн басыңыз"</string>
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Кулпуланган түзмөктү манжа изи менен ачуу"</string>
@@ -1624,7 +1624,7 @@
<string name="media_route_chooser_title" msgid="6646594924991269208">"Түзмөккө туташуу"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Тышкы экранга чыгаруу"</string>
<string name="media_route_chooser_searching" msgid="6119673534251329535">"Түзмөктөр изделүүдө..."</string>
- <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Жөндөөлөр"</string>
+ <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Параметрлер"</string>
<string name="media_route_controller_disconnect" msgid="7362617572732576959">"Ажыратуу"</string>
<string name="media_route_status_scanning" msgid="8045156315309594482">"Скандоодо..."</string>
<string name="media_route_status_connecting" msgid="5845597961412010540">"Туташууда..."</string>
@@ -1679,10 +1679,10 @@
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Атайын мүмкүнчүлүктөрдүн ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Параметрлер &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү катуулатуу/акырындатуу баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Параметрлер &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ооба"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Жок"</string>
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"КҮЙҮК"</string>
@@ -2069,7 +2069,7 @@
<string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Кийинчерээк эскертүү"</string>
<string name="review_notification_settings_dismiss" msgid="4160916504616428294">"Жабуу"</string>
<string name="notification_app_name_system" msgid="3045196791746735601">"Тутум"</string>
- <string name="notification_app_name_settings" msgid="9088548800899952531">"Жөндөөлөр"</string>
+ <string name="notification_app_name_settings" msgid="9088548800899952531">"Параметрлер"</string>
<string name="notification_appops_camera_active" msgid="8177643089272352083">"Камера"</string>
<string name="notification_appops_microphone_active" msgid="581333393214739332">"Микрофон"</string>
<string name="notification_appops_overlay_active" msgid="5571732753262836481">"экрандагы башка терезелердин үстүнөн көрсөтүлүүдө"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 42a477b4b1a8..9768208e5171 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1534,7 +1534,7 @@
<string name="add_account_button_label" msgid="322390749416414097">"Adicionar conta"</string>
<string name="number_picker_increment_button" msgid="7621013714795186298">"Aumentar"</string>
<string name="number_picker_decrement_button" msgid="5116948444762708204">"Diminuir"</string>
- <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e mantenha pressionado."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e pressione."</string>
<string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Deslize para cima para aumentar e para baixo para diminuir."</string>
<string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Aumentar minuto"</string>
<string name="time_picker_decrement_minute_button" msgid="230925389943411490">"Diminuir minuto"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 42a477b4b1a8..9768208e5171 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1534,7 +1534,7 @@
<string name="add_account_button_label" msgid="322390749416414097">"Adicionar conta"</string>
<string name="number_picker_increment_button" msgid="7621013714795186298">"Aumentar"</string>
<string name="number_picker_decrement_button" msgid="5116948444762708204">"Diminuir"</string>
- <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e mantenha pressionado."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> toque e pressione."</string>
<string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Deslize para cima para aumentar e para baixo para diminuir."</string>
<string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Aumentar minuto"</string>
<string name="time_picker_decrement_minute_button" msgid="230925389943411490">"Diminuir minuto"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 93d907ecfd1a..3b3fa06fd93c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -796,7 +796,7 @@
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"Nhà riêng"</item>
<item msgid="7740243458912727194">"Di động"</item>
- <item msgid="8526146065496663766">"Cơ quan"</item>
+ <item msgid="8526146065496663766">"Nơi làm việc"</item>
<item msgid="8150904584178569699">"Số fax cơ quan"</item>
<item msgid="4537253139152229577">"Số fax nhà riêng"</item>
<item msgid="6751245029698664340">"Số máy nhắn tin"</item>
@@ -805,24 +805,24 @@
</string-array>
<string-array name="emailAddressTypes">
<item msgid="7786349763648997741">"Nhà riêng"</item>
- <item msgid="435564470865989199">"Cơ quan"</item>
+ <item msgid="435564470865989199">"Nơi làm việc"</item>
<item msgid="4199433197875490373">"Khác"</item>
<item msgid="3233938986670468328">"Tùy chỉnh"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="3861463339764243038">"Nhà riêng"</item>
- <item msgid="5472578890164979109">"Cơ quan"</item>
+ <item msgid="5472578890164979109">"Nơi làm việc"</item>
<item msgid="5718921296646594739">"Khác"</item>
<item msgid="5523122236731783179">"Tùy chỉnh"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="588088543406993772">"Nhà riêng"</item>
- <item msgid="5503060422020476757">"Cơ quan"</item>
+ <item msgid="5503060422020476757">"Nơi làm việc"</item>
<item msgid="2530391194653760297">"Khác"</item>
<item msgid="7640927178025203330">"Tùy chỉnh"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="6144047813304847762">"Cơ quan"</item>
+ <item msgid="6144047813304847762">"Nơi làm việc"</item>
<item msgid="7402720230065674193">"Khác"</item>
<item msgid="808230403067569648">"Tùy chỉnh"</item>
</string-array>
@@ -839,7 +839,7 @@
<string name="phoneTypeCustom" msgid="5120365721260686814">"Tùy chỉnh"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"Nhà riêng"</string>
<string name="phoneTypeMobile" msgid="1178852541462086735">"Di động"</string>
- <string name="phoneTypeWork" msgid="6604967163358864607">"Cơ quan"</string>
+ <string name="phoneTypeWork" msgid="6604967163358864607">"Nơi làm việc"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"Số fax cơ quan"</string>
<string name="phoneTypeFaxHome" msgid="6678559953115904345">"Số fax nhà riêng"</string>
<string name="phoneTypePager" msgid="576402072263522767">"Số máy nhắn tin"</string>
@@ -863,16 +863,16 @@
<string name="eventTypeOther" msgid="530671238533887997">"Khác"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"Tùy chỉnh"</string>
<string name="emailTypeHome" msgid="1597116303154775999">"Nhà riêng"</string>
- <string name="emailTypeWork" msgid="2020095414401882111">"Cơ quan"</string>
+ <string name="emailTypeWork" msgid="2020095414401882111">"Nơi làm việc"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"Khác"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"Di Động"</string>
<string name="postalTypeCustom" msgid="5645590470242939129">"Tùy chỉnh"</string>
<string name="postalTypeHome" msgid="7562272480949727912">"Nhà riêng"</string>
- <string name="postalTypeWork" msgid="8553425424652012826">"Cơ quan"</string>
+ <string name="postalTypeWork" msgid="8553425424652012826">"Nơi làm việc"</string>
<string name="postalTypeOther" msgid="7094245413678857420">"Khác"</string>
<string name="imTypeCustom" msgid="5653384545085765570">"Tùy chỉnh"</string>
<string name="imTypeHome" msgid="6996507981044278216">"Nhà riêng"</string>
- <string name="imTypeWork" msgid="2099668940169903123">"Cơ quan"</string>
+ <string name="imTypeWork" msgid="2099668940169903123">"Nơi làm việc"</string>
<string name="imTypeOther" msgid="8068447383276219810">"Khác"</string>
<string name="imProtocolCustom" msgid="4437878287653764692">"Tùy chỉnh"</string>
<string name="imProtocolAim" msgid="4050198236506604378">"AIM"</string>
@@ -884,7 +884,7 @@
<string name="imProtocolIcq" msgid="2410325380427389521">"ICQ"</string>
<string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
- <string name="orgTypeWork" msgid="8684458700669564172">"Cơ quan"</string>
+ <string name="orgTypeWork" msgid="8684458700669564172">"Nơi làm việc"</string>
<string name="orgTypeOther" msgid="5450675258408005553">"Khác"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"Tùy chỉnh"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"Tùy chỉnh"</string>
@@ -904,7 +904,7 @@
<string name="relationTypeSpouse" msgid="6916682664436031703">"Vợ/chồng"</string>
<string name="sipAddressTypeCustom" msgid="6283889809842649336">"Tùy chỉnh"</string>
<string name="sipAddressTypeHome" msgid="5918441930656878367">"Nhà riêng"</string>
- <string name="sipAddressTypeWork" msgid="7873967986701216770">"Cơ quan"</string>
+ <string name="sipAddressTypeWork" msgid="7873967986701216770">"Nơi làm việc"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"Khác"</string>
<string name="quick_contacts_not_available" msgid="1262709196045052223">"Không tìm thấy ứng dụng nào để xem liên hệ này."</string>
<string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"Nhập mã PIN"</string>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index ea6e1f182fbf..a99ba152510e 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -72,8 +72,8 @@
<item name="secondary_content_alpha_material_dark" format="float" type="dimen">.7</item>
<item name="secondary_content_alpha_material_light" format="float" type="dimen">0.60</item>
- <item name="highlight_alpha_material_light" format="float" type="dimen">0.10</item>
- <item name="highlight_alpha_material_dark" format="float" type="dimen">0.10</item>
+ <item name="highlight_alpha_material_light" format="float" type="dimen">0.5</item>
+ <item name="highlight_alpha_material_dark" format="float" type="dimen">0.5</item>
<item name="highlight_alpha_material_colored" format="float" type="dimen">0.10</item>
<!-- Primary & accent colors -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2f5efd12a2ba..a6be07d0b780 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -576,6 +576,10 @@
rotations as the default behavior. -->
<bool name="config_allowAllRotations">false</bool>
+ <!-- If false and config_allowAllRotations is false, the screen will rotate to the natural
+ orientation of the device when the auto-rotate policy is toggled. -->
+ <bool name="config_useCurrentRotationOnRotationLockChange">false</bool>
+
<!-- If true, the direction rotation is applied to get to an application's requested
orientation is reversed. Normally, the model is that landscape is
clockwise from portrait; thus on a portrait device an app requesting
@@ -2074,6 +2078,9 @@
STREAM_MUSIC as if it's on TV platform. -->
<bool name="config_single_volume">false</bool>
+ <!-- Volume policy -->
+ <bool name="config_volume_down_to_enter_silent">false</bool>
+
<!-- The number of volume steps for the notification stream -->
<integer name="config_audio_notif_vol_steps">7</integer>
@@ -4972,9 +4979,8 @@
<!-- If face auth sends the user directly to home/last open app, or stays on keyguard -->
<bool name="config_faceAuthDismissesKeyguard">true</bool>
- <!-- Default value for whether a SFPS device is required to be interactive for fingerprint auth
- to unlock the device. -->
- <bool name="config_requireScreenOnToAuthEnabled">false</bool>
+ <!-- Default value for performant auth feature. -->
+ <bool name="config_performantAuthDefault">false</bool>
<!-- The component name for the default profile supervisor, which can be set as a profile owner
even after user setup is complete. The defined component should be used for supervision purposes
@@ -5353,6 +5359,9 @@
<!-- Whether using split screen aspect ratio as a default aspect ratio for unresizable apps. -->
<bool name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled">false</bool>
+ <!-- Whether using display aspect ratio as a default aspect ratio for all letterboxed apps. -->
+ <bool name="config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled">false</bool>
+
<!-- Whether the specific behaviour for translucent activities letterboxing is enabled.
TODO(b/255532890) Enable when ignoreOrientationRequest is set -->
<bool name="config_letterboxIsEnabledForTranslucentActivities">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 41281fa0d40f..be9f6d2448ba 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -321,6 +321,7 @@
<java-symbol type="bool" name="config_use_strict_phone_number_comparation_for_kazakhstan" />
<java-symbol type="integer" name="config_phonenumber_compare_min_match" />
<java-symbol type="bool" name="config_single_volume" />
+ <java-symbol type="bool" name="config_volume_down_to_enter_silent" />
<java-symbol type="bool" name="config_voice_capable" />
<java-symbol type="bool" name="config_requireCallCapableAccountForHandle" />
<java-symbol type="bool" name="config_user_notification_of_restrictied_mobile_access" />
@@ -1732,6 +1733,7 @@
<java-symbol type="attr" name="dialogTitleDecorLayout" />
<java-symbol type="attr" name="dialogTitleIconsDecorLayout" />
<java-symbol type="bool" name="config_allowAllRotations" />
+ <java-symbol type="bool" name="config_useCurrentRotationOnRotationLockChange"/>
<java-symbol type="bool" name="config_annoy_dianne" />
<java-symbol type="bool" name="config_startDreamImmediatelyOnDock" />
<java-symbol type="bool" name="config_carDockEnablesAccelerometer" />
@@ -2724,7 +2726,7 @@
<java-symbol type="array" name="config_face_acquire_vendor_biometricprompt_ignorelist" />
<java-symbol type="bool" name="config_faceAuthSupportsSelfIllumination" />
<java-symbol type="bool" name="config_faceAuthDismissesKeyguard" />
- <java-symbol type="bool" name="config_requireScreenOnToAuthEnabled" />
+ <java-symbol type="bool" name="config_performantAuthDefault" />
<!-- Face config -->
<java-symbol type="integer" name="config_faceMaxTemplatesPerUser" />
@@ -4462,6 +4464,7 @@
<java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
<java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" />
<java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" />
+ <java-symbol type="bool" name="config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled" />
<java-symbol type="bool" name="config_isCompatFakeFocusEnabled" />
<java-symbol type="bool" name="config_isWindowManagerCameraCompatTreatmentEnabled" />
<java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" />
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index ed2b10117308..3768063f2a91 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -368,4 +368,20 @@ public class PropertyInvalidatedCacheTests {
PropertyInvalidatedCache.MODULE_BLUETOOTH, "getState");
assertEquals(n1, "cache_key.bluetooth.get_state");
}
+
+ @Test
+ public void testOnTrimMemory() {
+ TestCache cache = new TestCache(MODULE, "trimMemoryTest");
+ // The cache is not active until it has been invalidated once.
+ cache.invalidateCache();
+ // Populate the cache with six entries.
+ for (int i = 0; i < 6; i++) {
+ cache.query(i);
+ }
+ // The maximum number of entries in TestCache is 4, so even though six entries were
+ // created, only four are retained.
+ assertEquals(4, cache.size());
+ PropertyInvalidatedCache.onTrimMemory();
+ assertEquals(0, cache.size());
+ }
}
diff --git a/core/tests/screenshothelpertests/Android.bp b/core/tests/screenshothelpertests/Android.bp
index 37af99c58d42..3c71e6e4247b 100644
--- a/core/tests/screenshothelpertests/Android.bp
+++ b/core/tests/screenshothelpertests/Android.bp
@@ -13,7 +13,7 @@ android_test {
srcs: [
"src/**/*.java",
],
-
+
static_libs: [
"frameworks-base-testutils",
"androidx.test.runner",
@@ -21,6 +21,7 @@ android_test {
"androidx.test.ext.junit",
"mockito-target-minus-junit4",
"platform-test-annotations",
+ "testng",
],
libs: [
diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
index 2719431a536e..5c9894ebd590 100644
--- a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
+++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
@@ -17,6 +17,7 @@
package com.android.internal.util;
import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;
@@ -31,9 +32,11 @@ import static org.mockito.Mockito.mock;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.os.Bundle;
+import android.hardware.HardwareBuffer;
import android.os.Handler;
import android.os.Looper;
import android.view.WindowManager;
@@ -79,30 +82,48 @@ public final class ScreenshotHelperTest {
@Test
public void testFullscreenScreenshot() {
- mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN,
+ mScreenshotHelper.takeScreenshot(
WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null);
}
@Test
+ public void testFullscreenScreenshotRequest() {
+ ScreenshotRequest request = new ScreenshotRequest.Builder(
+ TAKE_SCREENSHOT_FULLSCREEN, WindowManager.ScreenshotSource.SCREENSHOT_OTHER)
+ .build();
+ mScreenshotHelper.takeScreenshot(request, mHandler, null);
+ }
+
+ @Test
public void testProvidedImageScreenshot() {
- mScreenshotHelper.provideScreenshot(
- new Bundle(), new Rect(), Insets.of(0, 0, 0, 0), 1, 1, new ComponentName("", ""),
- WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null);
+ HardwareBuffer buffer = HardwareBuffer.create(
+ 10, 10, HardwareBuffer.RGBA_8888, 1, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB));
+ ScreenshotRequest request = new ScreenshotRequest.Builder(
+ TAKE_SCREENSHOT_PROVIDED_IMAGE, WindowManager.ScreenshotSource.SCREENSHOT_OTHER)
+ .setTopComponent(new ComponentName("", ""))
+ .setTaskId(1)
+ .setUserId(1)
+ .setBitmap(bitmap)
+ .setBoundsOnScreen(new Rect())
+ .setInsets(Insets.NONE)
+ .build();
+ mScreenshotHelper.takeScreenshot(request, mHandler, null);
}
@Test
public void testScreenshotTimesOut() {
long timeoutMs = 10;
+ ScreenshotRequest request = new ScreenshotRequest.Builder(
+ TAKE_SCREENSHOT_FULLSCREEN, WindowManager.ScreenshotSource.SCREENSHOT_OTHER)
+ .build();
CountDownLatch lock = new CountDownLatch(1);
- mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN,
- WindowManager.ScreenshotSource.SCREENSHOT_OTHER,
- mHandler,
- timeoutMs,
+ mScreenshotHelper.takeScreenshotInternal(request, mHandler,
uri -> {
assertNull(uri);
lock.countDown();
- });
+ }, timeoutMs);
try {
// Add tolerance for delay to prevent flakes.
diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotRequestTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotRequestTest.java
new file mode 100644
index 000000000000..30540a5f013b
--- /dev/null
+++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotRequestTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.util;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.os.UserHandle.USER_NULL;
+import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER;
+import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.ComponentName;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class ScreenshotRequestTest {
+ private final ComponentName mComponentName =
+ new ComponentName("android.test", "android.test.Component");
+
+ @Test
+ public void testSimpleScreenshot() {
+ ScreenshotRequest in =
+ new ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER).build();
+
+ Parcel parcel = Parcel.obtain();
+ in.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ScreenshotRequest out = ScreenshotRequest.CREATOR.createFromParcel(parcel);
+
+ assertEquals(TAKE_SCREENSHOT_FULLSCREEN, out.getType());
+ assertEquals(SCREENSHOT_OTHER, out.getSource());
+ assertNull("Top component was expected to be null", out.getTopComponent());
+ assertEquals(INVALID_TASK_ID, out.getTaskId());
+ assertEquals(USER_NULL, out.getUserId());
+ assertNull("Bitmap was expected to be null", out.getBitmap());
+ assertNull("Bounds were expected to be null", out.getBoundsInScreen());
+ assertEquals(Insets.NONE, out.getInsets());
+ }
+
+ @Test
+ public void testProvidedScreenshot() {
+ Bitmap bitmap = makeHardwareBitmap(50, 50);
+ ScreenshotRequest in =
+ new ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER)
+ .setTopComponent(mComponentName)
+ .setTaskId(2)
+ .setUserId(3)
+ .setBitmap(bitmap)
+ .setBoundsOnScreen(new Rect(10, 10, 60, 60))
+ .setInsets(Insets.of(2, 3, 4, 5))
+ .build();
+
+ Parcel parcel = Parcel.obtain();
+ in.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ScreenshotRequest out = ScreenshotRequest.CREATOR.createFromParcel(parcel);
+
+ assertEquals(TAKE_SCREENSHOT_PROVIDED_IMAGE, out.getType());
+ assertEquals(SCREENSHOT_OTHER, out.getSource());
+ assertEquals(mComponentName, out.getTopComponent());
+ assertEquals(2, out.getTaskId());
+ assertEquals(3, out.getUserId());
+ assertTrue("Bitmaps should be equal", out.getBitmap().sameAs(bitmap));
+ assertEquals(new Rect(10, 10, 60, 60), out.getBoundsInScreen());
+ assertEquals(Insets.of(2, 3, 4, 5), out.getInsets());
+ }
+
+ @Test
+ public void testProvidedScreenshot_nullBitmap() {
+ ScreenshotRequest.Builder inBuilder =
+ new ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER)
+ .setTopComponent(mComponentName)
+ .setTaskId(2)
+ .setUserId(3)
+ .setBoundsOnScreen(new Rect(10, 10, 60, 60))
+ .setInsets(Insets.of(2, 3, 4, 5));
+
+ assertThrows(IllegalStateException.class, inBuilder::build);
+ }
+
+ @Test
+ public void testFullScreenshot_withBitmap() {
+ // A bitmap added to a FULLSCREEN request will be ignored, but it's technically valid
+ Bitmap bitmap = makeHardwareBitmap(50, 50);
+ ScreenshotRequest in =
+ new ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER)
+ .setBitmap(bitmap)
+ .build();
+
+ Parcel parcel = Parcel.obtain();
+ in.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ScreenshotRequest out = ScreenshotRequest.CREATOR.createFromParcel(parcel);
+
+ assertEquals(TAKE_SCREENSHOT_FULLSCREEN, out.getType());
+ assertEquals(SCREENSHOT_OTHER, out.getSource());
+ assertNull(out.getTopComponent());
+ assertEquals(INVALID_TASK_ID, out.getTaskId());
+ assertEquals(USER_NULL, out.getUserId());
+ assertTrue("Bitmaps should be equal", out.getBitmap().sameAs(bitmap));
+ assertNull("Bounds expected to be null", out.getBoundsInScreen());
+ assertEquals(Insets.NONE, out.getInsets());
+ }
+
+ private Bitmap makeHardwareBitmap(int width, int height) {
+ HardwareBuffer buffer = HardwareBuffer.create(
+ width, height, HardwareBuffer.RGBA_8888, 1, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB));
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 417a27d0f506..7e2cac15f672 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -23,7 +23,6 @@ import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.animation.ValueAnimator;
-import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -983,9 +982,9 @@ public class RippleDrawable extends LayerDrawable {
RippleShader shader = new RippleShader();
// Grab the color for the current state and cut the alpha channel in
// half so that the ripple and background together yield full alpha.
- final int color = clampAlpha(mMaskColorFilter == null
+ final int color = mMaskColorFilter == null
? mState.mColor.getColorForState(getState(), Color.BLACK)
- : mMaskColorFilter.getColor());
+ : mMaskColorFilter.getColor();
final int effectColor = mState.mEffectColor.getColorForState(getState(), Color.MAGENTA);
final float noisePhase = AnimationUtils.currentAnimationTimeMillis();
shader.setColor(color, effectColor);
@@ -1008,13 +1007,6 @@ public class RippleDrawable extends LayerDrawable {
return properties;
}
- private int clampAlpha(@ColorInt int color) {
- if (Color.alpha(color) < 128) {
- return (color & 0x00FFFFFF) | 0x80000000;
- }
- return color;
- }
-
@Override
public void invalidateSelf() {
invalidateSelf(true);
@@ -1229,7 +1221,7 @@ public class RippleDrawable extends LayerDrawable {
// Grab the color for the current state and cut the alpha channel in
// half so that the ripple and background together yield full alpha.
- final int color = clampAlpha(mState.mColor.getColorForState(getState(), Color.BLACK));
+ final int color = mState.mColor.getColorForState(getState(), Color.BLACK);
final Paint p = mRipplePaint;
if (mMaskColorFilter != null) {
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 7d39c45d2530..800728b1e1e4 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="pip_phone_close" msgid="5783752637260411309">"Жабуу"</string>
<string name="pip_phone_expand" msgid="2579292903468287504">"Жайып көрсөтүү"</string>
- <string name="pip_phone_settings" msgid="5468987116750491918">"Жөндөөлөр"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Параметрлер"</string>
<string name="pip_phone_enter_split" msgid="7042877263880641911">"Экранды бөлүү режимине өтүү"</string>
<string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> – сүрөт ичиндеги сүрөт"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 96efeeb0c5eb..84840139d1a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -96,8 +96,7 @@ public class DisplayLayout {
/**
* Different from {@link #equals(Object)}, this method compares the basic geometry properties
- * of two {@link DisplayLayout} objects including width, height, rotation, density, cutout and
- * insets.
+ * of two {@link DisplayLayout} objects including width, height, rotation, density, cutout.
* @return {@code true} if the given {@link DisplayLayout} is identical geometry wise.
*/
public boolean isSameGeometry(@NonNull DisplayLayout other) {
@@ -105,8 +104,7 @@ public class DisplayLayout {
&& mHeight == other.mHeight
&& mRotation == other.mRotation
&& mDensityDpi == other.mDensityDpi
- && Objects.equals(mCutout, other.mCutout)
- && Objects.equals(mStableInsets, other.mStableInsets);
+ && Objects.equals(mCutout, other.mCutout);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 63b03ab76aac..a839a230ea6f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -36,6 +36,7 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArraySet;
@@ -261,6 +262,11 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
}
}
+ /** Get number of tasks that are marked as visible */
+ int getVisibleTaskCount() {
+ return mDesktopModeTaskRepository.getVisibleTaskCount();
+ }
+
@NonNull
private WindowContainerTransaction bringDesktopAppsToFront(boolean force) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -438,5 +444,15 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
DesktopModeController::showDesktopApps);
}
+
+ @Override
+ public int getVisibleTaskCount() throws RemoteException {
+ int[] result = new int[1];
+ executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
+ controller -> result[0] = controller.getVisibleTaskCount(),
+ true /* blocking */
+ );
+ return result[0];
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 600ccc17ecaa..47342c9f21ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -143,6 +143,13 @@ class DesktopModeTaskRepository {
}
/**
+ * Get number of tasks that are marked as visible
+ */
+ fun getVisibleTaskCount(): Int {
+ return visibleTasks.size
+ }
+
+ /**
* Add (or move if it already exists) the task to the top of the ordered list.
*/
fun addOrMoveFreeformTaskToTop(taskId: Int) {
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 9165f7012bb5..23033253eaf9 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
@@ -96,6 +96,11 @@ class DesktopTasksController(
}
}
+ /** Get number of tasks that are marked as visible */
+ fun getVisibleTaskCount(): Int {
+ return desktopModeTaskRepository.getVisibleTaskCount()
+ }
+
/** Move a task with given `taskId` to desktop */
fun moveToDesktop(taskId: Int) {
shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToDesktop(task) }
@@ -309,5 +314,16 @@ class DesktopTasksController(
Consumer(DesktopTasksController::showDesktopApps)
)
}
+
+ override fun getVisibleTaskCount(): Int {
+ val result = IntArray(1)
+ ExecutorUtils.executeRemoteCallWithTaskPermission(
+ controller,
+ "getVisibleTaskCount",
+ { controller -> result[0] = controller.getVisibleTaskCount() },
+ true /* blocking */
+ )
+ return result[0]
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index 5042bd6f2d65..d0739e14675f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -23,4 +23,7 @@ interface IDesktopMode {
/** Show apps on the desktop */
void showDesktopApps();
+
+ /** Get count of visible desktop tasks */
+ int getVisibleTaskCount();
} \ No newline at end of file
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 b9caf62012a6..26f47fcdaa44 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
@@ -114,7 +114,9 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
t.setPosition(leash, positionInParent.x, positionInParent.y);
t.setAlpha(leash, 1f);
t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
+ if (taskInfo.isVisible) {
+ t.show(leash);
+ }
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index e83854e22fa2..525beb166f7e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -616,7 +616,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
return;
}
int oldMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
- onDisplayChanged(
+ onDisplayChangedUncheck(
mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()),
false /* saveRestoreSnapFraction */);
int newMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
@@ -702,9 +702,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) {
- if (mPipBoundsState.getDisplayLayout().isSameGeometry(layout)) {
- return;
+ if (!mPipBoundsState.getDisplayLayout().isSameGeometry(layout)) {
+ onDisplayChangedUncheck(layout, saveRestoreSnapFraction);
}
+ }
+
+ private void onDisplayChangedUncheck(DisplayLayout layout, boolean saveRestoreSnapFraction) {
Runnable updateDisplayLayout = () -> {
final boolean fromRotation = Transitions.ENABLE_SHELL_TRANSITIONS
&& mPipBoundsState.getDisplayLayout().rotation() != layout.rotation();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 83bc7c0e6e7d..850c561c891f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -337,8 +337,10 @@ public class PipTouchHandler {
mMotionHelper.synchronizePinnedStackBounds();
reloadResources();
- // Recreate the dismiss target for the new orientation.
- mPipDismissTargetHandler.createOrUpdateDismissTarget();
+ if (mPipTaskOrganizer.isInPip()) {
+ // Recreate the dismiss target for the new orientation.
+ mPipDismissTargetHandler.createOrUpdateDismissTarget();
+ }
}
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
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 38099fc51d81..21eeaa2cafb3 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
@@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -535,17 +536,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
} else {
- try {
- adapter.getRunner().onAnimationCancelled(false /* isKeyguardOccluded */);
- ActivityTaskManager.getService().startActivityFromRecents(taskId, options2);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
+ taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
- return;
}
}
mStageCoordinator.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent,
@@ -586,17 +581,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
} else {
- try {
- adapter.getRunner().onAnimationCancelled(false /* isKeyguardOccluded */);
- pendingIntent1.send();
- } catch (RemoteException | PendingIntent.CanceledException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
+ pendingIntent2 = null;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
Toast.LENGTH_SHORT).show();
- return;
}
}
mStageCoordinator.startIntentsWithLegacyTransition(pendingIntent1, fillInIntent1, options1,
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 a6c4ac28c1fd..39cf5f1b95bd 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
@@ -629,9 +629,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
RemoteAnimationAdapter adapter, InstanceId instanceId) {
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 */);
+ wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
+ mSyncQueue.queue(wct);
+ return;
+ }
+
addActivityOptions(options1, mSideStage);
wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
-
startWithLegacyTransition(wct, pendingIntent2, fillInIntent2, options2, splitPosition,
splitRatio, adapter, instanceId);
}
@@ -666,9 +676,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
InstanceId instanceId) {
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);
+ return;
+ }
+
addActivityOptions(options1, mSideStage);
wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
-
startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter,
instanceId);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
index ff1d2990a82a..d5bb901259bd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
@@ -28,9 +28,11 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -82,13 +84,14 @@ public class TaskViewTest extends ShellTestCase {
@Mock
SyncTransactionQueue mSyncQueue;
@Mock
- TaskViewTransitions mTaskViewTransitions;
+ Transitions mTransitions;
SurfaceSession mSession;
SurfaceControl mLeash;
Context mContext;
TaskView mTaskView;
+ TaskViewTransitions mTaskViewTransitions;
@Before
public void setUp() {
@@ -118,6 +121,10 @@ public class TaskViewTest extends ShellTestCase {
return null;
}).when(mSyncQueue).runInSync(any());
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ doReturn(true).when(mTransitions).isRegistered();
+ }
+ mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions));
mTaskView = new TaskView(mContext, mOrganizer, mTaskViewTransitions, mSyncQueue);
mTaskView.setListener(mExecutor, mViewListener);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index 35cc16852b9f..7997a7ed7f7f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -334,6 +334,41 @@ public class DesktopModeControllerTest extends ShellTestCase {
}
@Test
+ public void testGetVisibleTaskCount_noTasks_returnsZero() {
+ assertThat(mController.getVisibleTaskCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetVisibleTaskCount_twoTasks_bothVisible_returnsTwo() {
+ RunningTaskInfo task1 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */);
+
+ RunningTaskInfo task2 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, true /* visible */);
+
+ assertThat(mController.getVisibleTaskCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testGetVisibleTaskCount_twoTasks_oneVisible_returnsOne() {
+ RunningTaskInfo task1 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task1.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */);
+
+ RunningTaskInfo task2 = createFreeformTask();
+ mDesktopModeTaskRepository.addActiveTask(task2.taskId);
+ mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
+ mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, false /* visible */);
+
+ assertThat(mController.getVisibleTaskCount()).isEqualTo(1);
+ }
+
+ @Test
public void testHandleTransitionRequest_desktopModeNotActive_returnsNull() {
when(DesktopModeStatus.isActive(any())).thenReturn(false);
WindowContainerTransaction wct = mController.handleRequest(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 1e43a5983821..45cb3a062cc5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -141,6 +141,36 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() {
}
@Test
+ fun getVisibleTaskCount() {
+ // No tasks, count is 0
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+
+ // New task increments count to 1
+ repo.updateVisibleFreeformTasks(taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+
+ // Visibility update to same task does not increase count
+ repo.updateVisibleFreeformTasks(taskId = 1, visible = true)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+
+ // Second task visible increments count
+ repo.updateVisibleFreeformTasks(taskId = 2, visible = true)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(2)
+
+ // Hiding a task decrements count
+ repo.updateVisibleFreeformTasks(taskId = 1, visible = false)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(1)
+
+ // Hiding all tasks leaves count at 0
+ repo.updateVisibleFreeformTasks(taskId = 2, visible = false)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+
+ // Hiding a not existing task, count remains at 0
+ repo.updateVisibleFreeformTasks(taskId = 999, visible = false)
+ assertThat(repo.getVisibleTaskCount()).isEqualTo(0)
+ }
+
+ @Test
fun addOrMoveFreeformTaskToTop_didNotExist_addsToTop() {
repo.addOrMoveFreeformTaskToTop(5)
repo.addOrMoveFreeformTaskToTop(6)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 4011d080564d..f16beeed57a3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -197,6 +197,27 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun getVisibleTaskCount_noTasks_returnsZero() {
+ assertThat(controller.getVisibleTaskCount()).isEqualTo(0)
+ }
+
+ @Test
+ fun getVisibleTaskCount_twoTasks_bothVisible_returnsTwo() {
+ setUpHomeTask()
+ setUpFreeformTask().also(::markTaskVisible)
+ setUpFreeformTask().also(::markTaskVisible)
+ assertThat(controller.getVisibleTaskCount()).isEqualTo(2)
+ }
+
+ @Test
+ fun getVisibleTaskCount_twoTasks_oneVisible_returnsOne() {
+ setUpHomeTask()
+ setUpFreeformTask().also(::markTaskVisible)
+ setUpFreeformTask().also(::markTaskHidden)
+ assertThat(controller.getVisibleTaskCount()).isEqualTo(1)
+ }
+
+ @Test
fun moveToDesktop() {
val task = setUpFullscreenTask()
controller.moveToDesktop(task)
@@ -224,7 +245,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
assertThat(hierarchyOps).hasSize(3)
assertReorderSequence(homeTask, freeformTask, fullscreenTask)
assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
- .isEqualTo(WINDOWING_MODE_FREEFORM)
+ .isEqualTo(WINDOWING_MODE_FREEFORM)
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 65e1ea881b26..0bb809d354dc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -29,11 +29,13 @@ import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -45,6 +47,8 @@ import android.app.ActivityManager;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
@@ -57,6 +61,7 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
@@ -65,6 +70,8 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.splitscreen.SplitScreen.SplitScreenListener;
+import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -98,11 +105,7 @@ public class StageCoordinatorTests extends ShellTestCase {
@Mock
private DisplayInsetsController mDisplayInsetsController;
@Mock
- private Transitions mTransitions;
- @Mock
private TransactionPool mTransactionPool;
- @Mock
- private ShellExecutor mMainExecutor;
private final Rect mBounds1 = new Rect(10, 20, 30, 40);
private final Rect mBounds2 = new Rect(5, 10, 15, 20);
@@ -112,11 +115,16 @@ public class StageCoordinatorTests extends ShellTestCase {
private SurfaceControl mRootLeash;
private ActivityManager.RunningTaskInfo mRootTask;
private StageCoordinator mStageCoordinator;
+ private Transitions mTransitions;
+ private final TestShellExecutor mMainExecutor = new TestShellExecutor();
+ private final ShellExecutor mAnimExecutor = new TestShellExecutor();
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
@Before
@UiThreadTest
public void setup() {
MockitoAnnotations.initMocks(this);
+ mTransitions = createTestTransitions();
mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool,
@@ -329,7 +337,20 @@ public class StageCoordinatorTests extends ShellTestCase {
mStageCoordinator.onFoldedStateChanged(true);
- verify(mStageCoordinator).onSplitScreenExit();
- verify(mMainStage).deactivate(any(WindowContainerTransaction.class), eq(false));
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ verify(mTaskOrganizer).startNewTransition(eq(TRANSIT_SPLIT_DISMISS), notNull());
+ } else {
+ verify(mStageCoordinator).onSplitScreenExit();
+ verify(mMainStage).deactivate(any(WindowContainerTransaction.class), eq(false));
+ }
+ }
+
+ private Transitions createTestTransitions() {
+ ShellInit shellInit = new ShellInit(mMainExecutor);
+ final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
+ mTaskOrganizer, mTransactionPool, mock(DisplayController.class), mMainExecutor,
+ mMainHandler, mAnimExecutor);
+ shellInit.init();
+ return t;
}
}
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index 2684fd969880..0f19fe81b379 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -88,7 +88,7 @@
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Планшетиңиз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам планшетиңизге кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Сыналгыңыз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам сыналгыңызга кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз."</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"Улантуу"</string>
- <string name="external_sources_settings" msgid="4046964413071713807">"Жөндөөлөр"</string>
+ <string name="external_sources_settings" msgid="4046964413071713807">"Параметрлер"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Тагынма колдонмолорду орнотуу/чыгаруу"</string>
<string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Колдонмолорду орноткучтун билдирмелери"</string>
<string name="notification_installation_success_message" msgid="6450467996056038442">"Ийгиликтүү орнотулду"</string>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml
index f4a893a1cd83..bcd6784bc8f8 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="settings_label" msgid="5948970810295631236">"Жөндөөлөр"</string>
+ <string name="settings_label" msgid="5948970810295631236">"Параметрлер"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 66aaa56b201a..b69fd5370e3b 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -247,7 +247,7 @@
</string-array>
<string-array name="track_frame_time_entries">
<item msgid="634406443901014984">"關閉"</item>
- <item msgid="1288760936356000927">"在螢幕上以列顯示"</item>
+ <item msgid="1288760936356000927">"在螢幕上顯示長條圖"</item>
<item msgid="5023908510820531131">"在「<xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>」指令中"</item>
</string-array>
<string-array name="debug_hw_overdraw_entries">
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index f5575170e92a..50d292192727 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -351,7 +351,7 @@
<string name="debug_app_set" msgid="6599535090477753651">"偵錯應用程式:<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="select_application" msgid="2543228890535466325">"選取應用程式"</string>
<string name="no_application" msgid="9038334538870247690">"無"</string>
- <string name="wait_for_debugger" msgid="7461199843335409809">"等待偵錯程式"</string>
+ <string name="wait_for_debugger" msgid="7461199843335409809">"等待偵錯工具"</string>
<string name="wait_for_debugger_summary" msgid="6846330006113363286">"執行受偵錯的應用程式之前,先等待偵錯程序附加完成"</string>
<string name="debug_input_category" msgid="7349460906970849771">"輸入"</string>
<string name="debug_drawing_category" msgid="5066171112313666619">"繪圖"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index 44a37f4ccaca..d4d2b48fcc04 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -18,6 +18,7 @@ package com.android.settingslib.display;
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -32,6 +33,9 @@ import android.view.WindowManagerGlobal;
import com.android.settingslib.R;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
/**
* Utility methods for working with display density.
@@ -70,120 +74,169 @@ public class DisplayDensityUtils {
*/
private static final int MIN_DIMENSION_DP = 320;
- private final String[] mEntries;
- private final int[] mValues;
+ private static final Predicate<DisplayInfo> INTERNAL_ONLY =
+ (info) -> info.type == Display.TYPE_INTERNAL;
- private final int mDefaultDensity;
- private final int mCurrentIndex;
+ private final Predicate<DisplayInfo> mPredicate;
+
+ private final DisplayManager mDisplayManager;
+
+ /**
+ * The text description of the density values of the default display.
+ */
+ private String[] mDefaultDisplayDensityEntries;
+
+ /**
+ * The density values of the default display.
+ */
+ private int[] mDefaultDisplayDensityValues;
+
+ /**
+ * The density values, indexed by display unique ID.
+ */
+ private final Map<String, int[]> mValuesPerDisplay = new HashMap();
+
+ private int mDefaultDensityForDefaultDisplay;
+ private int mCurrentIndex = -1;
public DisplayDensityUtils(Context context) {
- final int defaultDensity = DisplayDensityUtils.getDefaultDisplayDensity(
- Display.DEFAULT_DISPLAY);
- if (defaultDensity <= 0) {
- mEntries = null;
- mValues = null;
- mDefaultDensity = 0;
- mCurrentIndex = -1;
- return;
- }
+ this(context, INTERNAL_ONLY);
+ }
+
+ /**
+ * Creates an instance that stores the density values for the displays that satisfy
+ * the predicate.
+ * @param context The context
+ * @param predicate Determines what displays the density should be set for. The default display
+ * must satisfy this predicate.
+ */
+ public DisplayDensityUtils(Context context, Predicate predicate) {
+ mPredicate = predicate;
+ mDisplayManager = context.getSystemService(DisplayManager.class);
- final Resources res = context.getResources();
- DisplayInfo info = new DisplayInfo();
- context.getDisplayNoVerify().getDisplayInfo(info);
-
- final int currentDensity = info.logicalDensityDpi;
- int currentDensityIndex = -1;
-
- // Compute number of "larger" and "smaller" scales for this display.
- final int minDimensionPx = Math.min(info.logicalWidth, info.logicalHeight);
- final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
- final float maxScaleDimen = context.getResources().getFraction(
- R.fraction.display_density_max_scale, 1, 1);
- final float maxScale = Math.min(maxScaleDimen, maxDensity / (float) defaultDensity);
- final float minScale = context.getResources().getFraction(
- R.fraction.display_density_min_scale, 1, 1);
- final float minScaleInterval = context.getResources().getFraction(
- R.fraction.display_density_min_scale_interval, 1, 1);
- final int numLarger = (int) MathUtils.constrain((maxScale - 1) / minScaleInterval,
- 0, SUMMARIES_LARGER.length);
- final int numSmaller = (int) MathUtils.constrain((1 - minScale) / minScaleInterval,
- 0, SUMMARIES_SMALLER.length);
-
- String[] entries = new String[1 + numSmaller + numLarger];
- int[] values = new int[entries.length];
- int curIndex = 0;
-
- if (numSmaller > 0) {
- final float interval = (1 - minScale) / numSmaller;
- for (int i = numSmaller - 1; i >= 0; i--) {
- // Round down to a multiple of 2 by truncating the low bit.
- final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1;
- if (currentDensity == density) {
- currentDensityIndex = curIndex;
+ for (Display display : mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ DisplayInfo info = new DisplayInfo();
+ if (!display.getDisplayInfo(info)) {
+ Log.w(LOG_TAG, "Cannot fetch display info for display " + display.getDisplayId());
+ continue;
+ }
+ if (!mPredicate.test(info)) {
+ if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Predicate must not filter out the default "
+ + "display.");
}
- entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
- values[curIndex] = density;
- curIndex++;
+ continue;
}
- }
- if (currentDensity == defaultDensity) {
- currentDensityIndex = curIndex;
- }
- values[curIndex] = defaultDensity;
- entries[curIndex] = res.getString(SUMMARY_DEFAULT);
- curIndex++;
-
- if (numLarger > 0) {
- final float interval = (maxScale - 1) / numLarger;
- for (int i = 0; i < numLarger; i++) {
- // Round down to a multiple of 2 by truncating the low bit.
- final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1;
- if (currentDensity == density) {
- currentDensityIndex = curIndex;
+ final int defaultDensity = DisplayDensityUtils.getDefaultDensityForDisplay(
+ display.getDisplayId());
+ if (defaultDensity <= 0) {
+ Log.w(LOG_TAG, "Cannot fetch default density for display "
+ + display.getDisplayId());
+ continue;
+ }
+
+ final Resources res = context.getResources();
+
+ final int currentDensity = info.logicalDensityDpi;
+ int currentDensityIndex = -1;
+
+ // Compute number of "larger" and "smaller" scales for this display.
+ final int minDimensionPx = Math.min(info.logicalWidth, info.logicalHeight);
+ final int maxDensity =
+ DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
+ final float maxScaleDimen = context.getResources().getFraction(
+ R.fraction.display_density_max_scale, 1, 1);
+ final float maxScale = Math.min(maxScaleDimen, maxDensity / (float) defaultDensity);
+ final float minScale = context.getResources().getFraction(
+ R.fraction.display_density_min_scale, 1, 1);
+ final float minScaleInterval = context.getResources().getFraction(
+ R.fraction.display_density_min_scale_interval, 1, 1);
+ final int numLarger = (int) MathUtils.constrain((maxScale - 1) / minScaleInterval,
+ 0, SUMMARIES_LARGER.length);
+ final int numSmaller = (int) MathUtils.constrain((1 - minScale) / minScaleInterval,
+ 0, SUMMARIES_SMALLER.length);
+
+ String[] entries = new String[1 + numSmaller + numLarger];
+ int[] values = new int[entries.length];
+ int curIndex = 0;
+
+ if (numSmaller > 0) {
+ final float interval = (1 - minScale) / numSmaller;
+ for (int i = numSmaller - 1; i >= 0; i--) {
+ // Round down to a multiple of 2 by truncating the low bit.
+ final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1;
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
+ values[curIndex] = density;
+ curIndex++;
}
- values[curIndex] = density;
- entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
- curIndex++;
}
- }
- final int displayIndex;
- if (currentDensityIndex >= 0) {
- displayIndex = currentDensityIndex;
- } else {
- // We don't understand the current density. Must have been set by
- // someone else. Make room for another entry...
- int newLength = values.length + 1;
- values = Arrays.copyOf(values, newLength);
- values[curIndex] = currentDensity;
+ if (currentDensity == defaultDensity) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = defaultDensity;
+ entries[curIndex] = res.getString(SUMMARY_DEFAULT);
+ curIndex++;
- entries = Arrays.copyOf(entries, newLength);
- entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
+ if (numLarger > 0) {
+ final float interval = (maxScale - 1) / numLarger;
+ for (int i = 0; i < numLarger; i++) {
+ // Round down to a multiple of 2 by truncating the low bit.
+ final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1;
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = density;
+ entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
+ curIndex++;
+ }
+ }
- displayIndex = curIndex;
- }
+ final int displayIndex;
+ if (currentDensityIndex >= 0) {
+ displayIndex = currentDensityIndex;
+ } else {
+ // We don't understand the current density. Must have been set by
+ // someone else. Make room for another entry...
+ int newLength = values.length + 1;
+ values = Arrays.copyOf(values, newLength);
+ values[curIndex] = currentDensity;
- mDefaultDensity = defaultDensity;
- mCurrentIndex = displayIndex;
- mEntries = entries;
- mValues = values;
+ entries = Arrays.copyOf(entries, newLength);
+ entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
+
+ displayIndex = curIndex;
+ }
+
+ if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mDefaultDensityForDefaultDisplay = defaultDensity;
+ mCurrentIndex = displayIndex;
+ mDefaultDisplayDensityEntries = entries;
+ mDefaultDisplayDensityValues = values;
+ }
+ mValuesPerDisplay.put(info.uniqueId, values);
+ }
}
- public String[] getEntries() {
- return mEntries;
+ public String[] getDefaultDisplayDensityEntries() {
+ return mDefaultDisplayDensityEntries;
}
- public int[] getValues() {
- return mValues;
+ public int[] getDefaultDisplayDensityValues() {
+ return mDefaultDisplayDensityValues;
}
- public int getCurrentIndex() {
+ public int getCurrentIndexForDefaultDisplay() {
return mCurrentIndex;
}
- public int getDefaultDensity() {
- return mDefaultDensity;
+ public int getDefaultDensityForDefaultDisplay() {
+ return mDefaultDensityForDefaultDisplay;
}
/**
@@ -193,7 +246,7 @@ public class DisplayDensityUtils {
* @return the default density of the specified display, or {@code -1} if
* the display does not exist or the density could not be obtained
*/
- private static int getDefaultDisplayDensity(int displayId) {
+ private static int getDefaultDensityForDisplay(int displayId) {
try {
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
return wm.getInitialDisplayDensity(displayId);
@@ -203,19 +256,31 @@ public class DisplayDensityUtils {
}
/**
- * Asynchronously applies display density changes to the specified display.
+ * Asynchronously applies display density changes to the displays that satisfy the predicate.
* <p>
* The change will be applied to the user specified by the value of
* {@link UserHandle#myUserId()} at the time the method is called.
- *
- * @param displayId the identifier of the display to modify
*/
- public static void clearForcedDisplayDensity(final int displayId) {
+ public void clearForcedDisplayDensity() {
final int userId = UserHandle.myUserId();
AsyncTask.execute(() -> {
try {
- final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- wm.clearForcedDisplayDensityForUser(displayId, userId);
+ for (Display display : mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ int displayId = display.getDisplayId();
+ DisplayInfo info = new DisplayInfo();
+ if (!display.getDisplayInfo(info)) {
+ Log.w(LOG_TAG, "Unable to clear forced display density setting "
+ + "for display " + displayId);
+ continue;
+ }
+ if (!mPredicate.test(info)) {
+ continue;
+ }
+
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.clearForcedDisplayDensityForUser(displayId, userId);
+ }
} catch (RemoteException exc) {
Log.w(LOG_TAG, "Unable to clear forced display density setting");
}
@@ -223,20 +288,39 @@ public class DisplayDensityUtils {
}
/**
- * Asynchronously applies display density changes to the specified display.
+ * Asynchronously applies display density changes to the displays that satisfy the predicate.
* <p>
* The change will be applied to the user specified by the value of
* {@link UserHandle#myUserId()} at the time the method is called.
*
- * @param displayId the identifier of the display to modify
- * @param density the density to force for the specified display
+ * @param index The index of the density value
*/
- public static void setForcedDisplayDensity(final int displayId, final int density) {
+ public void setForcedDisplayDensity(final int index) {
final int userId = UserHandle.myUserId();
AsyncTask.execute(() -> {
try {
- final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- wm.setForcedDisplayDensityForUser(displayId, density, userId);
+ for (Display display : mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ int displayId = display.getDisplayId();
+ DisplayInfo info = new DisplayInfo();
+ if (!display.getDisplayInfo(info)) {
+ Log.w(LOG_TAG, "Unable to save forced display density setting "
+ + "for display " + displayId);
+ continue;
+ }
+ if (!mPredicate.test(info)) {
+ continue;
+ }
+ if (!mValuesPerDisplay.containsKey(info.uniqueId)) {
+ Log.w(LOG_TAG, "Unable to save forced display density setting "
+ + "for display " + info.uniqueId);
+ continue;
+ }
+
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.setForcedDisplayDensityForUser(displayId,
+ mValuesPerDisplay.get(info.uniqueId)[index], userId);
+ }
} catch (RemoteException exc) {
Log.w(LOG_TAG, "Unable to save forced display density setting");
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 75c92e000c4d..b6e006f3948a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -663,6 +663,20 @@
android:excludeFromRecents="true"
android:exported="true" />
+ <!-- started from Telecomm(CallsManager) -->
+ <activity
+ android:name=".telephony.ui.activity.SwitchToManagedProfileForCallActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:finishOnCloseSystemDialogs="true"
+ android:permission="android.permission.MODIFY_PHONE_STATE"
+ android:theme="@style/Theme.SystemUI.Dialog.Alert">
+ <intent-filter>
+ <action android:name="android.telecom.action.SHOW_SWITCH_TO_WORK_PROFILE_FOR_CALL_DIALOG" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<!-- platform logo easter egg activity -->
<activity
android:name=".DessertCase"
@@ -907,7 +921,7 @@
android:excludeFromRecents="true"
android:theme="@android:style/Theme.NoDisplay"
android:label="@string/note_task_button_label"
- android:icon="@drawable/ic_note_task_button">
+ android:icon="@drawable/ic_note_task_shortcut_widget">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index ee8d02301d5d..2910bba71341 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -5,46 +5,72 @@
SystemUI is a persistent process that provides UI for the system but outside
of the system_server process.
-The starting point for most of sysui code is a list of services that extend
-SystemUI that are started up by SystemUIApplication. These services then depend
-on some custom dependency injection provided by Dependency.
-
Inputs directed at sysui (as opposed to general listeners) generally come in
through IStatusBar. Outputs from sysui are through a variety of private APIs to
the android platform all over.
## SystemUIApplication
-When SystemUIApplication starts up, it will start up the services listed in
-config_systemUIServiceComponents or config_systemUIServiceComponentsPerUser.
+When SystemUIApplication starts up, it instantiates a Dagger graph from which
+various pieces of the application are built.
-Each of these services extend SystemUI. SystemUI provides them with a Context
-and gives them callbacks for onConfigurationChanged (this historically was
-the main path for onConfigurationChanged, now also happens through
-ConfigurationController). They also receive a callback for onBootCompleted
-since these objects may be started before the device has finished booting.
+To support customization, SystemUIApplication relies on the AndroidManifest.xml
+having an `android.app.AppComponentFactory` specified. Specifically, it relies
+on an `AppComponentFactory` that subclases `SystemUIAppComponentFactoryBase`.
+Implementations of this abstract base class must override
+`#createSystemUIInitializer(Context)` which returns a `SystemUIInitializer`.
+`SystemUIInitializer` primary job in turn is to intialize and return the Dagger
+root component back to the `SystemUIApplication`.
-Each SystemUI service is expected to be a major part of system ui and the
-goal is to minimize communication between them. So in general they should be
-relatively silo'd.
+Writing a custom `SystemUIAppComponentFactoryBase` and `SystemUIInitializer`,
+should be enough for most implementations to stand up a customized Dagger
+graph, and launch a custom version of SystemUI.
-## Dependencies
+## Dagger / Dependency Injection
-The first SystemUI service that is started should always be Dependency.
-Dependency provides a static method for getting a hold of dependencies that
-have a lifecycle that spans sysui. Dependency has code for how to create all
-dependencies manually added. SystemUIFactory is also capable of
-adding/replacing these dependencies.
+See [dagger.md](docs/dagger.md) and https://dagger.dev/.
-Dependencies are lazily initialized, so if a Dependency is never referenced at
-runtime, it will never be created.
+## CoreStartable
-If an instantiated dependency implements Dumpable it will be included in dumps
-of sysui (and bug reports), allowing it to include current state information.
-This is how \*Controllers dump state to bug reports.
+The starting point for most of SystemUI code is a list of classes that
+implement `CoreStartable` that are started up by SystemUIApplication.
+CoreStartables are like miniature services. They have their `#start` method
+called after being instantiated, and a reference to them is stored inside
+SystemUIApplication. They are in charge of their own behavior beyond this,
+registering and unregistering with the rest of the system as needed.
+
+`CoreStartable` also receives a callback for `#onBootCompleted`
+since these objects may be started before the device has finished booting.
-If an instantiated dependency implements ConfigurationChangeReceiver it will
-receive onConfigurationChange callbacks when the configuration changes.
+`CoreStartable` is an ideal place to add new features and functionality
+that does not belong directly under the umbrella of an existing feature.
+It is better to define a new `CoreStartable` than to stick unrelated
+initialization code together in catch-all methods.
+
+CoreStartables are tied to application startup via Dagger:
+
+```kotlin
+class FeatureStartable
+@Inject
+constructor(
+ /* ... */
+) : CoreStartable {
+ override fun start() {
+ // ...
+ }
+}
+
+@Module
+abstract class FeatureModule {
+ @Binds
+ @IntoMap
+ @ClassKey(FeatureStartable::class)
+ abstract fun bind(impl: FeatureStartable): CoreStartable
+}
+```
+
+Including `FeatureModule` in the Dagger graph such as this will ensure that
+`FeatureStartable` gets constructed and that its `#start` method is called.
## IStatusBar
@@ -64,12 +90,6 @@ across sysui. Such as when StatusBar calls CommandQueue#recomputeDisableFlags.
This is generally used a shortcut to directly trigger CommandQueue rather than
calling StatusManager and waiting for the call to come back to IStatusBar.
-## Default SystemUI services list
-
-### [com.android.systemui.Dependency](/packages/SystemUI/src/com/android/systemui/Dependency.java)
-
-Provides custom dependency injection.
-
### [com.android.systemui.util.NotificationChannels](/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java)
Creates/initializes the channels sysui uses when posting notifications.
@@ -88,11 +108,11 @@ activity. It provides this cached data to RecentsActivity when it is started.
Registers all the callbacks/listeners required to show the Volume dialog when
it should be shown.
-### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java)
+### [com.android.systemui.status.phone.CentralSurfaces](/packages/SystemUI/src/com/android/systemui/status/phone/CentralSurfaces.java)
This shows the UI for the status bar and the notification shade it contains.
It also contains a significant amount of other UI that interacts with these
-surfaces (keyguard, AOD, etc.). StatusBar also contains a notification listener
+surfaces (keyguard, AOD, etc.). CentralSurfaces also contains a notification listener
to receive notification callbacks.
### [com.android.systemui.usb.StorageNotification](/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java)
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index cd45b8ea9f61..60bfdb2ee379 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -16,6 +16,9 @@
},
{
"exclude-annotation": "android.platform.test.annotations.Postsubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
}
]
}
@@ -72,16 +75,16 @@
// Curious where your @Scenario tests will run?
//
// @Ignore: nowhere
- // @Staging or @FlakyTest: in staged-postsubmit, but not postsubmit or
- // presubmit
+ // @FlakyTest: in staged-postsubmit, but not blocking postsubmit or
+ // presubmit
// @Postsubmit: in postsubmit and staged-postsubmit, but not presubmit
// none of the above: in presubmit, postsubmit, and staged-postsubmit
//
- // Therefore, please annotate new tests with @Staging, then with @Postsubmit
- // once they're ready for postsubmit, then with neither once they're ready
- // for presubmit.
+ // Ideally, please annotate new tests with @FlakyTest, then with @Postsubmit
+ // once they're ready for postsubmit as they will immediately block go/android-platinum,
+ // then with neither once they're ready for presubmit.
//
- // If you don't use @Staging or @Postsubmit, your new test will immediately
+ // If you don't use @Postsubmit, your new test will immediately
// block presubmit, which is probably not what you want!
"sysui-platinum-postsubmit": [
{
@@ -98,6 +101,9 @@
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
}
]
}
@@ -130,6 +136,9 @@
},
{
"include-filter": "android.platform.test.scenario.sysui"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
}
]
}
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 8f70dcc02289..c729b09628af 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -301,10 +301,13 @@ class ActivityLaunchAnimator(
interface Callback {
/** Whether we are currently on the keyguard or not. */
- fun isOnKeyguard(): Boolean
+ @JvmDefault fun isOnKeyguard(): Boolean = false
/** Hide the keyguard and animate using [runner]. */
- fun hideKeyguardWithAnimation(runner: IRemoteAnimationRunner)
+ @JvmDefault
+ fun hideKeyguardWithAnimation(runner: IRemoteAnimationRunner) {
+ throw UnsupportedOperationException()
+ }
/* Get the background color of [task]. */
fun getBackgroundColor(task: TaskInfo): Int
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 9a9236be9c8a..a3ed0856c60a 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -237,13 +237,17 @@ constructor(
openedDialogs.firstOrNull {
it.dialog.window.decorView.viewRootImpl == controller.viewRoot
}
- val animateFrom =
+ val controller =
animatedParent?.dialogContentWithBackground?.let {
Controller.fromView(it, controller.cuj)
}
?: controller
- if (animatedParent == null && animateFrom !is LaunchableView) {
+ if (
+ animatedParent == null &&
+ controller is ViewDialogLaunchAnimatorController &&
+ controller.source !is LaunchableView
+ ) {
// Make sure the View we launch from implements LaunchableView to avoid visibility
// issues. Given that we don't own dialog decorViews so we can't enforce it for launches
// from a dialog.
@@ -272,7 +276,7 @@ constructor(
launchAnimator,
callback,
interactionJankMonitor,
- animateFrom,
+ controller,
onDialogDismissed = { openedDialogs.remove(it) },
dialog = dialog,
animateBackgroundBoundsChange,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
index 3d341af3b397..290328894439 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
@@ -33,9 +33,7 @@ private const val FONT_ITALIC_MIN = 0f
private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
private const val FONT_ITALIC_DEFAULT_VALUE = 0f
-/**
- * Provide interpolation of two fonts by adjusting font variation settings.
- */
+/** Provide interpolation of two fonts by adjusting font variation settings. */
class FontInterpolator {
/**
@@ -61,11 +59,14 @@ class FontInterpolator {
var index: Int,
val sortedAxes: MutableList<FontVariationAxis>
) {
- constructor(font: Font, axes: List<FontVariationAxis>) :
- this(font.sourceIdentifier,
- font.ttcIndex,
- axes.toMutableList().apply { sortBy { it.tag } }
- )
+ constructor(
+ font: Font,
+ axes: List<FontVariationAxis>
+ ) : this(
+ font.sourceIdentifier,
+ font.ttcIndex,
+ axes.toMutableList().apply { sortBy { it.tag } }
+ )
fun set(font: Font, axes: List<FontVariationAxis>) {
sourceId = font.sourceIdentifier
@@ -86,9 +87,7 @@ class FontInterpolator {
private val tmpInterpKey = InterpKey(null, null, 0f)
private val tmpVarFontKey = VarFontKey(0, 0, mutableListOf())
- /**
- * Linear interpolate the font variation settings.
- */
+ /** Linear interpolate the font variation settings. */
fun lerp(start: Font, end: Font, progress: Float): Font {
if (progress == 0f) {
return start
@@ -115,27 +114,34 @@ class FontInterpolator {
// this doesn't take much time since the variation axes is usually up to 5. If we need to
// support more number of axes, we may want to preprocess the font and store the sorted axes
// and also pre-fill the missing axes value with default value from 'fvar' table.
- val newAxes = lerp(startAxes, endAxes) { tag, startValue, endValue ->
- when (tag) {
- // TODO: Good to parse 'fvar' table for retrieving default value.
- TAG_WGHT -> adjustWeight(
- MathUtils.lerp(
+ val newAxes =
+ lerp(startAxes, endAxes) { tag, startValue, endValue ->
+ when (tag) {
+ // TODO: Good to parse 'fvar' table for retrieving default value.
+ TAG_WGHT ->
+ adjustWeight(
+ MathUtils.lerp(
startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
- progress))
- TAG_ITAL -> adjustItalic(
- MathUtils.lerp(
+ progress
+ )
+ )
+ TAG_ITAL ->
+ adjustItalic(
+ MathUtils.lerp(
startValue ?: FONT_ITALIC_DEFAULT_VALUE,
endValue ?: FONT_ITALIC_DEFAULT_VALUE,
- progress))
- else -> {
- require(startValue != null && endValue != null) {
- "Unable to interpolate due to unknown default axes value : $tag"
+ progress
+ )
+ )
+ else -> {
+ require(startValue != null && endValue != null) {
+ "Unable to interpolate due to unknown default axes value : $tag"
+ }
+ MathUtils.lerp(startValue, endValue, progress)
}
- MathUtils.lerp(startValue, endValue, progress)
}
}
- }
// Check if we already make font for this axes. This is typically happens if the animation
// happens backward.
@@ -149,9 +155,7 @@ class FontInterpolator {
// This is the first time to make the font for the axes. Build and store it to the cache.
// Font.Builder#build won't throw IOException since creating fonts from existing fonts will
// not do any IO work.
- val newFont = Font.Builder(start)
- .setFontVariationSettings(newAxes.toTypedArray())
- .build()
+ val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
interpCache[InterpKey(start, end, progress)] = newFont
verFontCache[VarFontKey(start, newAxes)] = newFont
return newFont
@@ -173,26 +177,28 @@ class FontInterpolator {
val tagA = if (i < start.size) start[i].tag else null
val tagB = if (j < end.size) end[j].tag else null
- val comp = when {
- tagA == null -> 1
- tagB == null -> -1
- else -> tagA.compareTo(tagB)
- }
-
- val axis = when {
- comp == 0 -> {
- val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
- FontVariationAxis(tagA, v)
+ val comp =
+ when {
+ tagA == null -> 1
+ tagB == null -> -1
+ else -> tagA.compareTo(tagB)
}
- comp < 0 -> {
- val v = filter(tagA!!, start[i++].styleValue, null)
- FontVariationAxis(tagA, v)
- }
- else -> { // comp > 0
- val v = filter(tagB!!, null, end[j++].styleValue)
- FontVariationAxis(tagB, v)
+
+ val axis =
+ when {
+ comp == 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
+ FontVariationAxis(tagA, v)
+ }
+ comp < 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, null)
+ FontVariationAxis(tagA, v)
+ }
+ else -> { // comp > 0
+ val v = filter(tagB!!, null, end[j++].styleValue)
+ FontVariationAxis(tagB, v)
+ }
}
- }
result.add(axis)
}
@@ -202,21 +208,21 @@ class FontInterpolator {
// For the performance reasons, we animate weight with FONT_WEIGHT_ANIMATION_STEP. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustWeight(value: Float) =
- coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
+ coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
// For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustItalic(value: Float) =
- coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP)
+ coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP)
private fun coerceInWithStep(v: Float, min: Float, max: Float, step: Float) =
- (v.coerceIn(min, max) / step).toInt() * step
+ (v.coerceIn(min, max) / step).toInt() * step
companion object {
private val EMPTY_AXES = arrayOf<FontVariationAxis>()
// Returns true if given two font instance can be interpolated.
fun canInterpolate(start: Font, end: Font) =
- start.ttcIndex == end.ttcIndex && start.sourceIdentifier == end.sourceIdentifier
+ start.ttcIndex == end.ttcIndex && start.sourceIdentifier == end.sourceIdentifier
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index dfac02d99c4d..26aa0e85cbd2 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
+import android.graphics.drawable.StateListDrawable
import android.util.Log
import android.view.GhostView
import android.view.View
@@ -35,6 +36,7 @@ import android.widget.FrameLayout
import com.android.internal.jank.InteractionJankMonitor
import java.util.LinkedList
import kotlin.math.min
+import kotlin.math.roundToInt
private const val TAG = "GhostedViewLaunchAnimatorController"
@@ -49,7 +51,9 @@ private const val TAG = "GhostedViewLaunchAnimatorController"
* Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
* whenever possible instead.
*/
-open class GhostedViewLaunchAnimatorController @JvmOverloads constructor(
+open class GhostedViewLaunchAnimatorController
+@JvmOverloads
+constructor(
/** The view that will be ghosted and from which the background will be extracted. */
private val ghostedView: View,
@@ -145,7 +149,8 @@ open class GhostedViewLaunchAnimatorController @JvmOverloads constructor(
val gradient = findGradientDrawable(drawable) ?: return 0f
// TODO(b/184121838): Support more than symmetric top & bottom radius.
- return gradient.cornerRadii?.get(CORNER_RADIUS_TOP_INDEX) ?: gradient.cornerRadius
+ val radius = gradient.cornerRadii?.get(CORNER_RADIUS_TOP_INDEX) ?: gradient.cornerRadius
+ return radius * ghostedView.scaleX
}
/** Return the current bottom corner radius of the background. */
@@ -154,7 +159,8 @@ open class GhostedViewLaunchAnimatorController @JvmOverloads constructor(
val gradient = findGradientDrawable(drawable) ?: return 0f
// TODO(b/184121838): Support more than symmetric top & bottom radius.
- return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius
+ val radius = gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius
+ return radius * ghostedView.scaleX
}
override fun createAnimatorState(): LaunchAnimator.State {
@@ -173,9 +179,13 @@ open class GhostedViewLaunchAnimatorController @JvmOverloads constructor(
ghostedView.getLocationOnScreen(ghostedViewLocation)
val insets = backgroundInsets
state.top = ghostedViewLocation[1] + insets.top
- state.bottom = ghostedViewLocation[1] + ghostedView.height - insets.bottom
+ state.bottom =
+ ghostedViewLocation[1] + (ghostedView.height * ghostedView.scaleY).roundToInt() -
+ insets.bottom
state.left = ghostedViewLocation[0] + insets.left
- state.right = ghostedViewLocation[0] + ghostedView.width - insets.right
+ state.right =
+ ghostedViewLocation[0] + (ghostedView.width * ghostedView.scaleX).roundToInt() -
+ insets.right
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -341,6 +351,10 @@ open class GhostedViewLaunchAnimatorController @JvmOverloads constructor(
}
}
+ if (drawable is StateListDrawable) {
+ return findGradientDrawable(drawable.current)
+ }
+
return null
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 5f1bb83715c2..fdab7490e476 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -36,8 +36,8 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
* Currently this class can provide text style animation for text weight and text size. For example
* the simple view that draws text with animating text size is like as follows:
*
- * <pre>
- * <code>
+ * <pre> <code>
+ * ```
* class SimpleTextAnimation : View {
* @JvmOverloads constructor(...)
*
@@ -53,83 +53,63 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
* animator.setTextStyle(-1 /* unchanged weight */, sizePx, animate)
* }
* }
- * </code>
- * </pre>
+ * ```
+ * </code> </pre>
*/
-class TextAnimator(
- layout: Layout,
- private val invalidateCallback: () -> Unit
-) {
+class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
// Following two members are for mutable for testing purposes.
public var textInterpolator: TextInterpolator = TextInterpolator(layout)
- public var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply {
- duration = DEFAULT_ANIMATION_DURATION
- addUpdateListener {
- textInterpolator.progress = it.animatedValue as Float
- invalidateCallback()
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- textInterpolator.rebase()
+ public var animator: ValueAnimator =
+ ValueAnimator.ofFloat(1f).apply {
+ duration = DEFAULT_ANIMATION_DURATION
+ addUpdateListener {
+ textInterpolator.progress = it.animatedValue as Float
+ invalidateCallback()
}
- override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
- })
- }
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ textInterpolator.rebase()
+ }
+ override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
+ }
+ )
+ }
sealed class PositionedGlyph {
- /**
- * Mutable X coordinate of the glyph position relative from drawing offset.
- */
+ /** Mutable X coordinate of the glyph position relative from drawing offset. */
var x: Float = 0f
- /**
- * Mutable Y coordinate of the glyph position relative from the baseline.
- */
+ /** Mutable Y coordinate of the glyph position relative from the baseline. */
var y: Float = 0f
- /**
- * The current line of text being drawn, in a multi-line TextView.
- */
+ /** The current line of text being drawn, in a multi-line TextView. */
var lineNo: Int = 0
- /**
- * Mutable text size of the glyph in pixels.
- */
+ /** Mutable text size of the glyph in pixels. */
var textSize: Float = 0f
- /**
- * Mutable color of the glyph.
- */
+ /** Mutable color of the glyph. */
var color: Int = 0
- /**
- * Immutable character offset in the text that the current font run start.
- */
+ /** Immutable character offset in the text that the current font run start. */
abstract var runStart: Int
protected set
- /**
- * Immutable run length of the font run.
- */
+ /** Immutable run length of the font run. */
abstract var runLength: Int
protected set
- /**
- * Immutable glyph index of the font run.
- */
+ /** Immutable glyph index of the font run. */
abstract var glyphIndex: Int
protected set
- /**
- * Immutable font instance for this font run.
- */
+ /** Immutable font instance for this font run. */
abstract var font: Font
protected set
- /**
- * Immutable glyph ID for this glyph.
- */
+ /** Immutable glyph ID for this glyph. */
abstract var glyphId: Int
protected set
}
@@ -147,20 +127,18 @@ class TextAnimator(
/**
* GlyphFilter applied just before drawing to canvas for tweaking positions and text size.
*
- * This callback is called for each glyphs just before drawing the glyphs. This function will
- * be called with the intrinsic position, size, color, glyph ID and font instance. You can
- * mutate the position, size and color for tweaking animations.
- * Do not keep the reference of passed glyph object. The interpolator reuses that object for
- * avoiding object allocations.
+ * This callback is called for each glyphs just before drawing the glyphs. This function will be
+ * called with the intrinsic position, size, color, glyph ID and font instance. You can mutate
+ * the position, size and color for tweaking animations. Do not keep the reference of passed
+ * glyph object. The interpolator reuses that object for avoiding object allocations.
*
- * Details:
- * The text is drawn with font run units. The font run is a text segment that draws with the
- * same font. The {@code runStart} and {@code runLimit} is a range of the font run in the text
- * that current glyph is in. Once the font run is determined, the system will convert characters
- * into glyph IDs. The {@code glyphId} is the glyph identifier in the font and
- * {@code glyphIndex} is the offset of the converted glyph array. Please note that the
- * {@code glyphIndex} is not a character index, because the character will not be converted to
- * glyph one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
+ * Details: The text is drawn with font run units. The font run is a text segment that draws
+ * with the same font. The {@code runStart} and {@code runLimit} is a range of the font run in
+ * the text that current glyph is in. Once the font run is determined, the system will convert
+ * characters into glyph IDs. The {@code glyphId} is the glyph identifier in the font and {@code
+ * glyphIndex} is the offset of the converted glyph array. Please note that the {@code
+ * glyphIndex} is not a character index, because the character will not be converted to glyph
+ * one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
* composed from multiple characters.
*
* Here is an example of font runs: "fin. 終わり"
@@ -193,7 +171,9 @@ class TextAnimator(
*/
var glyphFilter: GlyphCallback?
get() = textInterpolator.glyphFilter
- set(value) { textInterpolator.glyphFilter = value }
+ set(value) {
+ textInterpolator.glyphFilter = value
+ }
fun draw(c: Canvas) = textInterpolator.draw(c)
@@ -208,7 +188,7 @@ class TextAnimator(
* @param weight an optional text weight.
* @param textSize an optional font size.
* @param colors an optional colors array that must be the same size as numLines passed to
- * the TextInterpolator
+ * the TextInterpolator
* @param animate an optional boolean indicating true for showing style transition as animation,
* false for immediate style transition. True by default.
* @param duration an optional animation duration in milliseconds. This is ignored if animate is
@@ -237,10 +217,11 @@ class TextAnimator(
if (weight >= 0) {
// Paint#setFontVariationSettings creates Typeface instance from scratch. To reduce the
// memory impact, cache the typeface result.
- textInterpolator.targetPaint.typeface = typefaceCache.getOrElse(weight) {
- textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
- textInterpolator.targetPaint.typeface
- }
+ textInterpolator.targetPaint.typeface =
+ typefaceCache.getOrElse(weight) {
+ textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
+ textInterpolator.targetPaint.typeface
+ }
}
if (color != null) {
textInterpolator.targetPaint.color = color
@@ -249,22 +230,24 @@ class TextAnimator(
if (animate) {
animator.startDelay = delay
- animator.duration = if (duration == -1L) {
- DEFAULT_ANIMATION_DURATION
- } else {
- duration
- }
+ animator.duration =
+ if (duration == -1L) {
+ DEFAULT_ANIMATION_DURATION
+ } else {
+ duration
+ }
interpolator?.let { animator.interpolator = it }
if (onAnimationEnd != null) {
- val listener = object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- onAnimationEnd.run()
- animator.removeListener(this)
- }
- override fun onAnimationCancel(animation: Animator?) {
- animator.removeListener(this)
+ val listener =
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ onAnimationEnd.run()
+ animator.removeListener(this)
+ }
+ override fun onAnimationCancel(animation: Animator?) {
+ animator.removeListener(this)
+ }
}
- }
animator.addListener(listener)
}
animator.start()
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 0448c818f765..341784e26257 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -26,12 +26,8 @@ import android.util.MathUtils
import com.android.internal.graphics.ColorUtils
import java.lang.Math.max
-/**
- * Provide text style linear interpolation for plain text.
- */
-class TextInterpolator(
- layout: Layout
-) {
+/** Provide text style linear interpolation for plain text. */
+class TextInterpolator(layout: Layout) {
/**
* Returns base paint used for interpolation.
@@ -64,12 +60,11 @@ class TextInterpolator(
var baseFont: Font,
var targetFont: Font
) {
- val length: Int get() = end - start
+ val length: Int
+ get() = end - start
}
- /**
- * A class represents text layout of a single run.
- */
+ /** A class represents text layout of a single run. */
private class Run(
val glyphIds: IntArray,
val baseX: FloatArray, // same length as glyphIds
@@ -79,12 +74,8 @@ class TextInterpolator(
val fontRuns: List<FontRun>
)
- /**
- * A class represents text layout of a single line.
- */
- private class Line(
- val runs: List<Run>
- )
+ /** A class represents text layout of a single line. */
+ private class Line(val runs: List<Run>)
private var lines = listOf<Line>()
private val fontInterpolator = FontInterpolator()
@@ -106,8 +97,8 @@ class TextInterpolator(
/**
* The layout used for drawing text.
*
- * Only non-styled text is supported. Even if the given layout is created from Spanned, the
- * span information is not used.
+ * Only non-styled text is supported. Even if the given layout is created from Spanned, the span
+ * information is not used.
*
* The paint objects used for interpolation are not changed by this method call.
*
@@ -122,6 +113,9 @@ class TextInterpolator(
shapeText(value)
}
+ var shapedText: String = ""
+ private set
+
init {
// shapeText needs to be called after all members are initialized.
shapeText(layout)
@@ -130,8 +124,8 @@ class TextInterpolator(
/**
* Recalculate internal text layout for interpolation.
*
- * Whenever the target paint is modified, call this method to recalculate internal
- * text layout used for interpolation.
+ * Whenever the target paint is modified, call this method to recalculate internal text layout
+ * used for interpolation.
*/
fun onTargetPaintModified() {
updatePositionsAndFonts(shapeText(layout, targetPaint), updateBase = false)
@@ -140,8 +134,8 @@ class TextInterpolator(
/**
* Recalculate internal text layout for interpolation.
*
- * Whenever the base paint is modified, call this method to recalculate internal
- * text layout used for interpolation.
+ * Whenever the base paint is modified, call this method to recalculate internal text layout
+ * used for interpolation.
*/
fun onBasePaintModified() {
updatePositionsAndFonts(shapeText(layout, basePaint), updateBase = true)
@@ -152,11 +146,11 @@ class TextInterpolator(
*
* The text interpolator does not calculate all the text position by text shaper due to
* performance reasons. Instead, the text interpolator shape the start and end state and
- * calculate text position of the middle state by linear interpolation. Due to this trick,
- * the text positions of the middle state is likely different from the text shaper result.
- * So, if you want to start animation from the middle state, you will see the glyph jumps due to
- * this trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different
- * from text shape result of weight 550.
+ * calculate text position of the middle state by linear interpolation. Due to this trick, the
+ * text positions of the middle state is likely different from the text shaper result. So, if
+ * you want to start animation from the middle state, you will see the glyph jumps due to this
+ * trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different from
+ * text shape result of weight 550.
*
* After calling this method, do not call onBasePaintModified() since it reshape the text and
* update the base state. As in above notice, the text shaping result at current progress is
@@ -168,8 +162,8 @@ class TextInterpolator(
* 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>
+ * <pre> <code>
+ * ```
* val interp = TextInterpolator(layout)
*
* // Interpolate between weight 200 to 400.
@@ -199,9 +193,8 @@ class TextInterpolator(
* // progress is 0.5
* animator.start()
* }
- * </code>
- * </pre>
- *
+ * ```
+ * </code> </pre>
*/
fun rebase() {
if (progress == 0f) {
@@ -263,69 +256,73 @@ class TextInterpolator(
}
var maxRunLength = 0
- lines = baseLayout.zip(targetLayout) { baseLine, targetLine ->
- val runs = baseLine.zip(targetLine) { base, target ->
-
- require(base.glyphCount() == target.glyphCount()) {
- "Inconsistent glyph count at line ${lines.size}"
- }
-
- val glyphCount = base.glyphCount()
-
- // Good to recycle the array if the existing array can hold the new layout result.
- val glyphIds = IntArray(glyphCount) {
- base.getGlyphId(it).also { baseGlyphId ->
- require(baseGlyphId == target.getGlyphId(it)) {
- "Inconsistent glyph ID at $it in line ${lines.size}"
+ lines =
+ baseLayout.zip(targetLayout) { baseLine, targetLine ->
+ val runs =
+ baseLine.zip(targetLine) { base, target ->
+ require(base.glyphCount() == target.glyphCount()) {
+ "Inconsistent glyph count at line ${lines.size}"
}
- }
- }
- val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
- val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
- val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
- val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
-
- // Calculate font runs
- val fontRun = mutableListOf<FontRun>()
- if (glyphCount != 0) {
- var start = 0
- var baseFont = base.getFont(start)
- var targetFont = target.getFont(start)
- require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
- "Cannot interpolate font at $start ($baseFont vs $targetFont)"
- }
-
- for (i in 1 until glyphCount) {
- val nextBaseFont = base.getFont(i)
- val nextTargetFont = target.getFont(i)
-
- if (baseFont !== nextBaseFont) {
- require(targetFont !== nextTargetFont) {
- "Base font has changed at $i but target font has not changed."
+ val glyphCount = base.glyphCount()
+
+ // Good to recycle the array if the existing array can hold the new layout
+ // result.
+ val glyphIds =
+ IntArray(glyphCount) {
+ base.getGlyphId(it).also { baseGlyphId ->
+ require(baseGlyphId == target.getGlyphId(it)) {
+ "Inconsistent glyph ID at $it in line ${lines.size}"
+ }
+ }
}
- // Font transition point. push run and reset context.
- fontRun.add(FontRun(start, i, baseFont, targetFont))
- maxRunLength = max(maxRunLength, i - start)
- baseFont = nextBaseFont
- targetFont = nextTargetFont
- start = i
+
+ val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
+ val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
+ val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
+ val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
+
+ // Calculate font runs
+ val fontRun = mutableListOf<FontRun>()
+ if (glyphCount != 0) {
+ var start = 0
+ var baseFont = base.getFont(start)
+ var targetFont = target.getFont(start)
require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
"Cannot interpolate font at $start ($baseFont vs $targetFont)"
}
- } else { // baseFont === nextBaseFont
- require(targetFont === nextTargetFont) {
- "Base font has not changed at $i but target font has changed."
+
+ for (i in 1 until glyphCount) {
+ val nextBaseFont = base.getFont(i)
+ val nextTargetFont = target.getFont(i)
+
+ if (baseFont !== nextBaseFont) {
+ require(targetFont !== nextTargetFont) {
+ "Base font has changed at $i but target font is unchanged."
+ }
+ // Font transition point. push run and reset context.
+ fontRun.add(FontRun(start, i, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, i - start)
+ baseFont = nextBaseFont
+ targetFont = nextTargetFont
+ start = i
+ require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+ "Cannot interpolate font at $start" +
+ " ($baseFont vs $targetFont)"
+ }
+ } else { // baseFont === nextBaseFont
+ require(targetFont === nextTargetFont) {
+ "Base font is unchanged at $i but target font has changed."
+ }
+ }
}
+ fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, glyphCount - start)
}
+ Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
}
- fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
- maxRunLength = max(maxRunLength, glyphCount - start)
- }
- Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
+ Line(runs)
}
- Line(runs)
- }
// Update float array used for drawing.
if (tmpPositionArray.size < maxRunLength * 2) {
@@ -357,9 +354,9 @@ class TextInterpolator(
if (glyphFilter == null) {
for (i in run.start until run.end) {
tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
+ MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
}
c.drawGlyphs(line.glyphIds, run.start, tmpPositionArray, 0, run.length, font, paint)
return
@@ -388,13 +385,14 @@ class TextInterpolator(
tmpPaintForGlyph.color = tmpGlyph.color
c.drawGlyphs(
- line.glyphIds,
- prevStart,
- tmpPositionArray,
- 0,
- i - prevStart,
- font,
- tmpPaintForGlyph)
+ line.glyphIds,
+ prevStart,
+ tmpPositionArray,
+ 0,
+ i - prevStart,
+ font,
+ tmpPaintForGlyph
+ )
prevStart = i
arrayIndex = 0
}
@@ -404,13 +402,14 @@ class TextInterpolator(
}
c.drawGlyphs(
- line.glyphIds,
- prevStart,
- tmpPositionArray,
- 0,
- run.end - prevStart,
- font,
- tmpPaintForGlyph)
+ line.glyphIds,
+ prevStart,
+ tmpPositionArray,
+ 0,
+ run.end - prevStart,
+ font,
+ tmpPaintForGlyph
+ )
}
private fun updatePositionsAndFonts(
@@ -418,9 +417,7 @@ class TextInterpolator(
updateBase: Boolean
) {
// Update target positions with newly calculated text layout.
- check(layoutResult.size == lines.size) {
- "The new layout result has different line count."
- }
+ check(layoutResult.size == lines.size) { "The new layout result has different line count." }
lines.zip(layoutResult) { line, runs ->
line.runs.zip(runs) { lineRun, newGlyphs ->
@@ -436,7 +433,7 @@ class TextInterpolator(
}
require(newFont === newGlyphs.getFont(i)) {
"The new layout has different font run." +
- " $newFont vs ${newGlyphs.getFont(i)} at $i"
+ " $newFont vs ${newGlyphs.getFont(i)} at $i"
}
}
@@ -444,7 +441,7 @@ class TextInterpolator(
// check new font can be interpolatable with base font.
require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
"New font cannot be interpolated with existing font. $newFont," +
- " ${run.baseFont}"
+ " ${run.baseFont}"
}
if (updateBase) {
@@ -480,14 +477,13 @@ class TextInterpolator(
}
// Shape the text and stores the result to out argument.
- private fun shapeText(
- layout: Layout,
- paint: TextPaint
- ): List<List<PositionedGlyphs>> {
+ private fun shapeText(layout: Layout, paint: TextPaint): List<List<PositionedGlyphs>> {
+ var text = StringBuilder()
val out = mutableListOf<List<PositionedGlyphs>>()
for (lineNo in 0 until layout.lineCount) { // Shape all lines.
val lineStart = layout.getLineStart(lineNo)
- var count = layout.getLineEnd(lineNo) - lineStart
+ val lineEnd = layout.getLineEnd(lineNo)
+ var count = lineEnd - lineStart
// Do not render the last character in the line if it's a newline and unprintable
val last = lineStart + count - 1
if (last > lineStart && last < layout.text.length && layout.text[last] == '\n') {
@@ -495,19 +491,28 @@ class TextInterpolator(
}
val runs = mutableListOf<PositionedGlyphs>()
- TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
- paint) { _, _, glyphs, _ ->
- runs.add(glyphs)
- }
+ TextShaper.shapeText(
+ layout.text,
+ lineStart,
+ count,
+ layout.textDirectionHeuristic,
+ paint
+ ) { _, _, glyphs, _ -> runs.add(glyphs) }
out.add(runs)
+
+ if (lineNo > 0) {
+ text.append("\n")
+ }
+ text.append(layout.text.substring(lineStart, lineEnd))
}
+ shapedText = text.toString()
return out
}
}
private fun Layout.getDrawOrigin(lineNo: Int) =
- if (getParagraphDirection(lineNo) == Layout.DIR_LEFT_TO_RIGHT) {
- getLineLeft(lineNo)
- } else {
- getLineRight(lineNo)
- }
+ if (getParagraphDirection(lineNo) == Layout.DIR_LEFT_TO_RIGHT) {
+ getLineLeft(lineNo)
+ } else {
+ getLineRight(lineNo)
+ }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
index 46d5a5c0af8c..9257f99efe96 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
@@ -25,7 +25,7 @@ import com.android.internal.jank.InteractionJankMonitor
/** A [DialogLaunchAnimator.Controller] that can animate a [View] from/to a dialog. */
class ViewDialogLaunchAnimatorController
internal constructor(
- private val source: View,
+ internal val source: View,
override val cuj: DialogCuj?,
) : DialogLaunchAnimator.Controller {
override val viewRoot: ViewRootImpl?
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetector.kt
new file mode 100644
index 000000000000..1f6e60359eb8
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetector.kt
@@ -0,0 +1,150 @@
+/*
+ * 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 org.jetbrains.uast.UElement
+import org.jetbrains.uast.UFile
+import org.jetbrains.uast.UImportStatement
+
+/**
+ * Detects violations of the Dependency Rule of Clean Architecture.
+ *
+ * The rule states that code in each layer may only depend on code in the same layer or the layer
+ * directly "beneath" that layer in the layer diagram.
+ *
+ * In System UI, we have three layers; from top to bottom, they are: ui, domain, and data. As a
+ * convention, was used packages with those names to place code in the appropriate layer. We also
+ * make an exception and allow for shared models to live under a separate package named "shared" to
+ * avoid code duplication.
+ *
+ * For more information, please see go/sysui-arch.
+ */
+@Suppress("UnstableApiUsage")
+class CleanArchitectureDependencyViolationDetector : Detector(), Detector.UastScanner {
+ override fun getApplicableUastTypes(): List<Class<out UElement>> {
+ return listOf(UFile::class.java)
+ }
+
+ override fun createUastHandler(context: JavaContext): UElementHandler {
+ return object : UElementHandler() {
+ override fun visitFile(node: UFile) {
+ // Check which Clean Architecture layer this file belongs to:
+ matchingLayer(node.packageName)?.let { layer ->
+ // The file matches with a Clean Architecture layer. Let's check all of its
+ // imports.
+ node.imports.forEach { importStatement ->
+ visitImportStatement(context, layer, importStatement)
+ }
+ }
+ }
+ }
+ }
+
+ private fun visitImportStatement(
+ context: JavaContext,
+ layer: Layer,
+ importStatement: UImportStatement,
+ ) {
+ val importText = importStatement.importReference?.asSourceString() ?: return
+ val importedLayer = matchingLayer(importText) ?: return
+
+ // Now check whether the layer of the file may depend on the layer of the import.
+ if (!layer.mayDependOn(importedLayer)) {
+ context.report(
+ issue = ISSUE,
+ scope = importStatement,
+ location = context.getLocation(importStatement),
+ message =
+ "The ${layer.packageNamePart} layer may not depend on" +
+ " the ${importedLayer.packageNamePart} layer.",
+ )
+ }
+ }
+
+ private fun matchingLayer(packageName: String): Layer? {
+ val packageNameParts = packageName.split(".").toSet()
+ return Layer.values()
+ .filter { layer -> packageNameParts.contains(layer.packageNamePart) }
+ .takeIf { it.size == 1 }
+ ?.first()
+ }
+
+ private enum class Layer(
+ val packageNamePart: String,
+ val canDependOn: Set<Layer>,
+ ) {
+ SHARED(
+ packageNamePart = "shared",
+ canDependOn = emptySet(), // The shared layer may not depend on any other layer.
+ ),
+ DATA(
+ packageNamePart = "data",
+ canDependOn = setOf(SHARED),
+ ),
+ DOMAIN(
+ packageNamePart = "domain",
+ canDependOn = setOf(SHARED, DATA),
+ ),
+ UI(
+ packageNamePart = "ui",
+ canDependOn = setOf(DOMAIN, SHARED),
+ ),
+ ;
+
+ fun mayDependOn(otherLayer: Layer): Boolean {
+ return this == otherLayer || canDependOn.contains(otherLayer)
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ val ISSUE =
+ Issue.create(
+ id = "CleanArchitectureDependencyViolation",
+ briefDescription = "Violation of the Clean Architecture Dependency Rule.",
+ explanation =
+ """
+ Following the \"Dependency Rule\" from Clean Architecture, every layer of code \
+ can only depend code in its own layer or code in the layer directly \
+ \"beneath\" it. Therefore, the UI layer can only depend on the" Domain layer \
+ and the Domain layer can only depend on the Data layer. We" do make an \
+ exception to allow shared models to exist and be shared across layers by \
+ placing them under shared/model, which should be done with care. For more \
+ information about Clean Architecture in System UI, please see go/sysui-arch. \
+ NOTE: if your code is not using Clean Architecture, please feel free to ignore \
+ this warning.
+ """,
+ category = Category.CORRECTNESS,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(
+ CleanArchitectureDependencyViolationDetector::class.java,
+ Scope.JAVA_FILE_SCOPE,
+ ),
+ )
+ }
+}
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 3f334c1cdb9c..254a6fb4714f 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
@@ -27,9 +27,11 @@ import com.google.auto.service.AutoService
class SystemUIIssueRegistry : IssueRegistry() {
override val issues: List<Issue>
- get() = listOf(
+ get() =
+ listOf(
BindServiceOnMainThreadDetector.ISSUE,
BroadcastSentViaContextDetector.ISSUE,
+ CleanArchitectureDependencyViolationDetector.ISSUE,
SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
NonInjectedMainThreadDetector.ISSUE,
@@ -37,7 +39,7 @@ class SystemUIIssueRegistry : IssueRegistry() {
SoftwareBitmapDetector.ISSUE,
NonInjectedServiceDetector.ISSUE,
StaticSettingsProviderDetector.ISSUE
- )
+ )
override val api: Int
get() = CURRENT_API
@@ -45,9 +47,9 @@ class SystemUIIssueRegistry : IssueRegistry() {
get() = 8
override val vendor: Vendor =
- Vendor(
- vendorName = "Android",
- feedbackUrl = "http://b/issues/new?component=78010",
- contact = "jernej@google.com"
- )
+ Vendor(
+ vendorName = "Android",
+ feedbackUrl = "http://b/issues/new?component=78010",
+ contact = "jernej@google.com"
+ )
}
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
new file mode 100644
index 000000000000..a4b59fd8e086
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt
@@ -0,0 +1,296 @@
+/*
+ * 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.checks.infrastructure.TestMode
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Ignore
+import org.junit.Test
+
+@Suppress("UnstableApiUsage")
+@Ignore("b/254533331")
+class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTest() {
+ override fun getDetector(): Detector {
+ return CleanArchitectureDependencyViolationDetector()
+ }
+
+ override fun getIssues(): List<Issue> {
+ return listOf(
+ CleanArchitectureDependencyViolationDetector.ISSUE,
+ )
+ }
+
+ @Test
+ fun `No violations`() {
+ lint()
+ .files(
+ *LEGITIMATE_FILES,
+ )
+ .issues(
+ CleanArchitectureDependencyViolationDetector.ISSUE,
+ )
+ .run()
+ .expectWarningCount(0)
+ }
+
+ @Test
+ fun `Violation - domain depends on ui`() {
+ lint()
+ .files(
+ *LEGITIMATE_FILES,
+ TestFiles.kotlin(
+ """
+ package test.domain.interactor
+
+ import test.ui.viewmodel.ViewModel
+
+ class BadClass(
+ private val viewModel: ViewModel,
+ )
+ """.trimIndent()
+ )
+ )
+ .issues(
+ CleanArchitectureDependencyViolationDetector.ISSUE,
+ )
+ .testModes(TestMode.DEFAULT)
+ .run()
+ .expectWarningCount(1)
+ .expect(
+ expectedText =
+ """
+ src/test/domain/interactor/BadClass.kt:3: Warning: The domain layer may not depend on the ui layer. [CleanArchitectureDependencyViolation]
+ import test.ui.viewmodel.ViewModel
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """,
+ )
+ }
+
+ @Test
+ fun `Violation - ui depends on data`() {
+ lint()
+ .files(
+ *LEGITIMATE_FILES,
+ TestFiles.kotlin(
+ """
+ package test.ui.viewmodel
+
+ import test.data.repository.Repository
+
+ class BadClass(
+ private val repository: Repository,
+ )
+ """.trimIndent()
+ )
+ )
+ .issues(
+ CleanArchitectureDependencyViolationDetector.ISSUE,
+ )
+ .testModes(TestMode.DEFAULT)
+ .run()
+ .expectWarningCount(1)
+ .expect(
+ expectedText =
+ """
+ src/test/ui/viewmodel/BadClass.kt:3: Warning: The ui layer may not depend on the data layer. [CleanArchitectureDependencyViolation]
+ import test.data.repository.Repository
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """,
+ )
+ }
+
+ @Test
+ fun `Violation - shared depends on all other layers`() {
+ lint()
+ .files(
+ *LEGITIMATE_FILES,
+ TestFiles.kotlin(
+ """
+ package test.shared.model
+
+ import test.data.repository.Repository
+ import test.domain.interactor.Interactor
+ import test.ui.viewmodel.ViewModel
+
+ class BadClass(
+ private val repository: Repository,
+ private val interactor: Interactor,
+ private val viewmodel: ViewModel,
+ )
+ """.trimIndent()
+ )
+ )
+ .issues(
+ CleanArchitectureDependencyViolationDetector.ISSUE,
+ )
+ .testModes(TestMode.DEFAULT)
+ .run()
+ .expectWarningCount(3)
+ .expect(
+ expectedText =
+ """
+ src/test/shared/model/BadClass.kt:3: Warning: The shared layer may not depend on the data layer. [CleanArchitectureDependencyViolation]
+ import test.data.repository.Repository
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ src/test/shared/model/BadClass.kt:4: Warning: The shared layer may not depend on the domain layer. [CleanArchitectureDependencyViolation]
+ import test.domain.interactor.Interactor
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ src/test/shared/model/BadClass.kt:5: Warning: The shared layer may not depend on the ui layer. [CleanArchitectureDependencyViolation]
+ import test.ui.viewmodel.ViewModel
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 3 warnings
+ """,
+ )
+ }
+
+ @Test
+ fun `Violation - data depends on domain`() {
+ lint()
+ .files(
+ *LEGITIMATE_FILES,
+ TestFiles.kotlin(
+ """
+ package test.data.repository
+
+ import test.domain.interactor.Interactor
+
+ class BadClass(
+ private val interactor: Interactor,
+ )
+ """.trimIndent()
+ )
+ )
+ .issues(
+ CleanArchitectureDependencyViolationDetector.ISSUE,
+ )
+ .testModes(TestMode.DEFAULT)
+ .run()
+ .expectWarningCount(1)
+ .expect(
+ expectedText =
+ """
+ src/test/data/repository/BadClass.kt:3: Warning: The data layer may not depend on the domain layer. [CleanArchitectureDependencyViolation]
+ import test.domain.interactor.Interactor
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """,
+ )
+ }
+
+ companion object {
+ private val MODEL_FILE =
+ TestFiles.kotlin(
+ """
+ package test.shared.model
+
+ import test.some.other.thing.SomeOtherThing
+
+ data class Model(
+ private val name: String,
+ )
+ """.trimIndent()
+ )
+ private val REPOSITORY_FILE =
+ TestFiles.kotlin(
+ """
+ package test.data.repository
+
+ import test.shared.model.Model
+ import test.some.other.thing.SomeOtherThing
+
+ class Repository {
+ private val models = listOf(
+ Model("one"),
+ Model("two"),
+ Model("three"),
+ )
+
+ fun getModels(): List<Model> {
+ return models
+ }
+ }
+ """.trimIndent()
+ )
+ private val INTERACTOR_FILE =
+ TestFiles.kotlin(
+ """
+ package test.domain.interactor
+
+ import test.data.repository.Repository
+ import test.shared.model.Model
+
+ class Interactor(
+ private val repository: Repository,
+ ) {
+ fun getModels(): List<Model> {
+ return repository.getModels()
+ }
+ }
+ """.trimIndent()
+ )
+ private val VIEW_MODEL_FILE =
+ TestFiles.kotlin(
+ """
+ package test.ui.viewmodel
+
+ import test.domain.interactor.Interactor
+ import test.some.other.thing.SomeOtherThing
+
+ class ViewModel(
+ private val interactor: Interactor,
+ ) {
+ fun getNames(): List<String> {
+ return interactor.getModels().map { model -> model.name }
+ }
+ }
+ """.trimIndent()
+ )
+ private val NON_CLEAN_ARCHITECTURE_FILE =
+ TestFiles.kotlin(
+ """
+ package test.some.other.thing
+
+ import test.data.repository.Repository
+ import test.domain.interactor.Interactor
+ import test.ui.viewmodel.ViewModel
+
+ class SomeOtherThing {
+ init {
+ val viewModel = ViewModel(
+ interactor = Interactor(
+ repository = Repository(),
+ ),
+ )
+ }
+ }
+ """.trimIndent()
+ )
+ private val LEGITIMATE_FILES =
+ arrayOf(
+ MODEL_FILE,
+ REPOSITORY_FILE,
+ INTERACTOR_FILE,
+ VIEW_MODEL_FILE,
+ NON_CLEAN_ARCHITECTURE_FILE,
+ )
+ }
+}
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 7f1c78fc47ff..e4e9c4648f14 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
@@ -178,6 +178,9 @@ object CustomizationProviderContract {
/** Flag denoting whether the customizable clocks feature is enabled. */
const val FLAG_NAME_CUSTOM_CLOCKS_ENABLED = "is_custom_clocks_feature_enabled"
+ /** Flag denoting whether the Wallpaper preview should use the full screen UI. */
+ const val FLAG_NAME_WALLPAPER_FULLSCREEN_PREVIEW = "wallpaper_fullscreen_preview"
+
object Columns {
/** String. Unique ID for the flag. */
const val NAME = "name"
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index 89170139e21c..9b4c21efb27f 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -8,105 +8,110 @@ Go read about Dagger 2.
- [User's guide](https://google.github.io/dagger/users-guide)
-TODO: Add some links.
-
## State of the world
-Dagger 2 has been turned on for SystemUI and a early first pass has been taken
-for converting everything in [Dependency.java](packages/systemui/src/com/android/systemui/Dependency.java)
-to use Dagger. Since a lot of SystemUI depends on Dependency, stubs have been added to Dependency
-to proxy any gets through to the instances provided by dagger, this will allow migration of SystemUI
-through a number of CLs.
+Dagger 2 has been turned on for SystemUI and much of
+[Dependency.java](../src/com/android/systemui/Dependency.java)
+has been converted to use Dagger. Since a lot of SystemUI depends on Dependency,
+stubs have been added to Dependency to proxy any gets through to the instances
+provided by dagger, this will allow migration of SystemUI through a number of CLs.
### How it works in SystemUI
+There are three high level "scopes" of concern in SystemUI. They all represent
+singleton scopes, but serve different purposes.
+
+* `@Singleton` - Instances that are shared everywhere. There isn't a lot of
+ code in this scope. Things like the main thread, and Android Framework
+ provided instances mostly.
+* `@WMShell` - WindowManager related code in the SystemUI process. We don't
+ want this code relying on the rest of SystemUI, and we don't want the rest
+ of SystemUI peeking into its internals, so it runs in its own Subcomponent.
+* `@SysUISingleton` - Most of what would be considered "SystemUI". Most feature
+ work by SystemUI developers goes into this scope. Useful interfaces from
+ WindowManager are made available inside this Subcomponent.
+
+The root dagger graph is created by an instance of `SystemUIInitializer`.
+See [README.md](../README.md) for more details.
For the classes that we're using in Dependency and are switching to dagger, the
equivalent dagger version is using `@Singleton` and therefore only has one instance.
To have the single instance span all of SystemUI and be easily accessible for
other components, there is a single root `@Component` that exists that generates
-these. The component lives in [SystemUIFactory](packages/systemui/src/com/android/systemui/SystemUIFactory.java)
-and is called `SystemUIRootComponent`.
+these. The component lives in
+[ReferenceGlobalRootComponent.java](../src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java).
-```java
+### Adding a new injectable object
-@Singleton
-@Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class,
- ContextHolder.class})
-public interface SystemUIRootComponent {
- @Singleton
- Dependency.DependencyInjector createDependency();
+First annotate the constructor with `@Inject`. Also annotate it with
+`@SysUISingleton` if only one instance should be created.
+
+```kotlin
+@SysUISingleton
+class FeatureStartable
+@Inject
+constructor(
+/* ... */
+) {
+ // ...
}
```
-The root component is composed of root modules, which in turn provide the global singleton
-dependencies across all of SystemUI.
-
-- `SystemUIFactory` `@Provides` dependencies that need to be overridden by SystemUI
-variants (like other form factors e.g. Car).
-
-- `DependencyBinder` creates the mapping from interfaces to implementation classes.
+If you have an interface class and an implementation class, Dagger needs to
+know how to map it. The simplest way to do this is to add an `@Binds` method
+in a module. The type of the return value tells dagger which dependency it's
+providing:
-- `DependencyProvider` provides or binds any remaining depedencies required.
-
-### Adding injection to a new SystemUI object
-
-SystemUI object are made injectable by adding an entry in `SystemUIBinder`. SystemUIApplication uses
-information in that file to locate and construct an instance of the requested SystemUI class.
-
-### Adding a new injectable object
-
-First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one
-instance should be created.
-
-```java
-@Singleton
-public class SomethingController {
- @Inject
- public SomethingController(Context context,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
- // context and mainHandler will be automatically populated.
- }
+```kotlin
+@Module
+abstract class FeatureModule {
+ @Binds
+ abstract fun bindsFeature(impl: FeatureImpl): Feature
}
```
-If you have an interface class and an implementation class, dagger needs to know
-how to map it. The simplest way to do this is to add an `@Provides` method to
-DependencyProvider. The type of the return value tells dagger which dependency it's providing.
-
-```java
-public class DependencyProvider {
- //...
- @Singleton
- @Provides
- public SomethingController provideSomethingController(Context context,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
- return new SomethingControllerImpl(context, mainHandler);
- }
+If you have a class that you want to make injectable that has can not
+be easily constructed by Dagger, write a `@Provides` method for it:
+
+```kotlin
+@Module
+abstract class FeatureModule {
+ @Module
+ companion object {
+ @Provides
+ fun providesFeature(ctx: Context): Feature {
+ return FeatureImpl.constructFromContext(ctx)
+ }
+ }
}
```
-If you need to access this from Dependency#get, then add an adapter to Dependency
-that maps to the instance provided by Dagger. The changes should be similar
-to the following diff.
+### Module Organization
-```java
-public class Dependency {
- //...
- @Inject Lazy<SomethingController> mSomethingController;
- //...
- public void start() {
- //...
- mProviders.put(SomethingController.class, mSomethingController::get);
- }
-}
-```
+Please define your modules on _at least_ per-package level. If the scope of a
+package grows to encompass a great number of features, create per-feature
+modules.
+
+**Do not create catch-all modules.** Those quickly grow unwieldy and
+unmaintainable. Any that exist today should be refactored into obsolescence.
+
+You can then include your module in one of three places:
+
+1) Within another module that depends on it. Ideally, this creates a clean
+ dependency graph between features and utilities.
+2) For features that should exist in all versions of SystemUI (AOSP and
+ any variants), include the module in
+ [SystemUIModule.java](../src/com/android/systemui/dagger/SystemUIModule.java).
+3) For features that should exist only in AOSP, include the module in
+ [ReferenceSystemUIModule.java](../src/com/android/systemui/dagger/ReferenceSystemUIModule.java).
+ Similarly, if you are working on a custom version of SystemUI and have code
+ specific to your version, include it in a module specific to your version.
### Using injection with Fragments
Fragments are created as part of the FragmentManager, so they need to be
setup so the manager knows how to create them. To do that, add a method
to com.android.systemui.fragments.FragmentService$FragmentCreator that
-returns your fragment class. Thats all thats required, once the method
+returns your fragment class. That is all that is required, once the method
exists, FragmentService will automatically pick it up and use injection
whenever your fragment needs to be created.
@@ -123,48 +128,11 @@ then the FragmentHostManager can do this for you.
FragmentHostManager.get(view).create(NavigationBarFragment.class);
```
-### Using injection with Views
-
-DO NOT ADD NEW VIEW INJECTION. VIEW INJECTION IS BEING ACTIVELY DEPRECATED.
-
-Needing to inject objects into your View's constructor generally implies you
-are doing more work in your presentation layer than is advisable.
-Instead, create an injected controller for you view, inject into the
-controller, and then attach the view to the controller after inflation.
-
-View injection generally causes headaches while testing, as inflating a view
-(which may in turn inflate other views) implicitly causes a Dagger graph to
-be stood up, which may or may not contain the appropriately
-faked/mocked/stubbed objects. It is a hard to control process.
-
## Updating Dagger2
We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates
when that repository is updated.
-
-*Deprecated:*
-
-Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded
-into
-[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/)
-
-The following commands should work, substituting in the version that you are looking for:
-
-````
-cd prebuilts/tools/common/m2/repository/com/google/dagger/
-
-wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger/2.28.1/
-
-wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.28.1/
-
-wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-spi/2.28.1/
-
-wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.28.1/
-````
-
-Then update `prebuilts/tools/common/m2/Android.bp` to point at your new jars.
## TODO List
- - Eliminate usages of Dependency#get
- - Add links in above TODO
+ - Eliminate usages of Dependency#get: http://b/hotlists/3940788
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index f53e3f6b2ea9..1f0081278092 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -1,8 +1,5 @@
+packages/SystemUI
--packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
--packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
-packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
--packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.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
@@ -322,8 +319,8 @@
-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/gesture/GenericGestureDetector.kt
--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
-packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
-packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index dee0f5cd1979..314c736e2e44 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -80,6 +80,7 @@ internal class HueSubtract(val amountDegrees: Double) : Hue {
internal class HueVibrantSecondary() : Hue {
val hueToRotations = listOf(Pair(0, 18), Pair(41, 15), Pair(61, 10), Pair(101, 12),
Pair(131, 15), Pair(181, 18), Pair(251, 15), Pair(301, 12), Pair(360, 12))
+
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -88,6 +89,7 @@ internal class HueVibrantSecondary() : Hue {
internal class HueVibrantTertiary() : Hue {
val hueToRotations = listOf(Pair(0, 35), Pair(41, 30), Pair(61, 20), Pair(101, 25),
Pair(131, 30), Pair(181, 35), Pair(251, 30), Pair(301, 25), Pair(360, 25))
+
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -96,6 +98,7 @@ internal class HueVibrantTertiary() : Hue {
internal class HueExpressiveSecondary() : Hue {
val hueToRotations = listOf(Pair(0, 45), Pair(21, 95), Pair(51, 45), Pair(121, 20),
Pair(151, 45), Pair(191, 90), Pair(271, 45), Pair(321, 45), Pair(360, 45))
+
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -104,6 +107,7 @@ internal class HueExpressiveSecondary() : Hue {
internal class HueExpressiveTertiary() : Hue {
val hueToRotations = listOf(Pair(0, 120), Pair(21, 120), Pair(51, 20), Pair(121, 45),
Pair(151, 20), Pair(191, 15), Pair(271, 20), Pair(321, 120), Pair(360, 120))
+
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -148,11 +152,11 @@ internal class TonalSpec(val hue: Hue = HueSource(), val chroma: Chroma) {
}
internal class CoreSpec(
- val a1: TonalSpec,
- val a2: TonalSpec,
- val a3: TonalSpec,
- val n1: TonalSpec,
- val n2: TonalSpec
+ val a1: TonalSpec,
+ val a2: TonalSpec,
+ val a3: TonalSpec,
+ val n1: TonalSpec,
+ val n2: TonalSpec
)
enum class Style(internal val coreSpec: CoreSpec) {
@@ -214,51 +218,86 @@ enum class Style(internal val coreSpec: CoreSpec) {
)),
}
+class TonalPalette {
+ val shadeKeys = listOf(10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
+ val allShades: List<Int>
+ val allShadesMapped: Map<Int, Int>
+ val baseColor: Int
+
+ internal constructor(spec: TonalSpec, seedColor: Int) {
+ val seedCam = Cam.fromInt(seedColor)
+ allShades = spec.shades(seedCam)
+ allShadesMapped = shadeKeys.zip(allShades).toMap()
+
+ val h = spec.hue.get(seedCam).toFloat()
+ val c = spec.chroma.get(seedCam).toFloat()
+ baseColor = ColorUtils.CAMToColor(h, c, CamUtils.lstarFromInt(seedColor))
+ }
+
+ val s10: Int get() = this.allShades[0]
+ val s50: Int get() = this.allShades[1]
+ val s100: Int get() = this.allShades[2]
+ val s200: Int get() = this.allShades[3]
+ val s300: Int get() = this.allShades[4]
+ val s400: Int get() = this.allShades[5]
+ val s500: Int get() = this.allShades[6]
+ val s600: Int get() = this.allShades[7]
+ val s700: Int get() = this.allShades[8]
+ val s800: Int get() = this.allShades[9]
+ val s900: Int get() = this.allShades[10]
+ val s1000: Int get() = this.allShades[11]
+}
+
class ColorScheme(
- @ColorInt val seed: Int,
- val darkTheme: Boolean,
- val style: Style = Style.TONAL_SPOT
+ @ColorInt val seed: Int,
+ val darkTheme: Boolean,
+ val style: Style = Style.TONAL_SPOT
) {
- val accent1: List<Int>
- val accent2: List<Int>
- val accent3: List<Int>
- val neutral1: List<Int>
- val neutral2: List<Int>
+ val accent1: TonalPalette
+ val accent2: TonalPalette
+ val accent3: TonalPalette
+ val neutral1: TonalPalette
+ val neutral2: TonalPalette
constructor(@ColorInt seed: Int, darkTheme: Boolean) :
this(seed, darkTheme, Style.TONAL_SPOT)
@JvmOverloads
constructor(
- wallpaperColors: WallpaperColors,
- darkTheme: Boolean,
- style: Style = Style.TONAL_SPOT
+ wallpaperColors: WallpaperColors,
+ darkTheme: Boolean,
+ style: Style = Style.TONAL_SPOT
) :
this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style)
+ val allHues: List<TonalPalette>
+ get() {
+ return listOf(accent1, accent2, accent3, neutral1, neutral2)
+ }
+
val allAccentColors: List<Int>
get() {
val allColors = mutableListOf<Int>()
- allColors.addAll(accent1)
- allColors.addAll(accent2)
- allColors.addAll(accent3)
+ allColors.addAll(accent1.allShades)
+ allColors.addAll(accent2.allShades)
+ allColors.addAll(accent3.allShades)
return allColors
}
val allNeutralColors: List<Int>
get() {
val allColors = mutableListOf<Int>()
- allColors.addAll(neutral1)
- allColors.addAll(neutral2)
+ allColors.addAll(neutral1.allShades)
+ allColors.addAll(neutral2.allShades)
return allColors
}
val backgroundColor
- get() = ColorUtils.setAlphaComponent(if (darkTheme) neutral1[8] else neutral1[0], 0xFF)
+ get() = ColorUtils.setAlphaComponent(if (darkTheme) neutral1.s700 else neutral1.s10, 0xFF)
val accentColor
- get() = ColorUtils.setAlphaComponent(if (darkTheme) accent1[2] else accent1[6], 0xFF)
+ get() = ColorUtils.setAlphaComponent(if (darkTheme) accent1.s100 else accent1.s500, 0xFF)
init {
val proposedSeedCam = Cam.fromInt(seed)
@@ -269,24 +308,26 @@ class ColorScheme(
} else {
seed
}
- val camSeed = Cam.fromInt(seedArgb)
- accent1 = style.coreSpec.a1.shades(camSeed)
- accent2 = style.coreSpec.a2.shades(camSeed)
- accent3 = style.coreSpec.a3.shades(camSeed)
- neutral1 = style.coreSpec.n1.shades(camSeed)
- neutral2 = style.coreSpec.n2.shades(camSeed)
+
+ accent1 = TonalPalette(style.coreSpec.a1, seedArgb)
+ accent2 = TonalPalette(style.coreSpec.a2, seedArgb)
+ accent3 = TonalPalette(style.coreSpec.a3, seedArgb)
+ neutral1 = TonalPalette(style.coreSpec.n1, seedArgb)
+ neutral2 = TonalPalette(style.coreSpec.n2, seedArgb)
}
+ val shadeCount get() = this.accent1.allShades.size
+
override fun toString(): String {
return "ColorScheme {\n" +
" seed color: ${stringForColor(seed)}\n" +
" style: $style\n" +
" palettes: \n" +
- " ${humanReadable("PRIMARY", accent1)}\n" +
- " ${humanReadable("SECONDARY", accent2)}\n" +
- " ${humanReadable("TERTIARY", accent3)}\n" +
- " ${humanReadable("NEUTRAL", neutral1)}\n" +
- " ${humanReadable("NEUTRAL VARIANT", neutral2)}\n" +
+ " ${humanReadable("PRIMARY", accent1.allShades)}\n" +
+ " ${humanReadable("SECONDARY", accent2.allShades)}\n" +
+ " ${humanReadable("TERTIARY", accent3.allShades)}\n" +
+ " ${humanReadable("NEUTRAL", neutral1.allShades)}\n" +
+ " ${humanReadable("NEUTRAL VARIANT", neutral2.allShades)}\n" +
"}"
}
@@ -385,7 +426,8 @@ class ColorScheme(
val existingSeedNearby = seeds.find {
val hueA = intToCam[int]!!.hue
val hueB = intToCam[it]!!.hue
- hueDiff(hueA, hueB) < i } != null
+ hueDiff(hueA, hueB) < i
+ } != null
if (existingSeedNearby) {
continue
}
@@ -460,9 +502,9 @@ class ColorScheme(
}
private fun huePopulations(
- camByColor: Map<Int, Cam>,
- populationByColor: Map<Int, Double>,
- filter: Boolean = true
+ camByColor: Map<Int, Cam>,
+ populationByColor: Map<Int, Double>,
+ filter: Boolean = true
): List<Double> {
val huePopulation = List(size = 360, init = { 0.0 }).toMutableList()
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index 7709f210f22f..fb1c454de70d 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -29,6 +29,7 @@ java_library {
"src/**/*.java",
"src/**/*.kt",
"bcsmartspace/src/**/*.java",
+ "bcsmartspace/src/**/*.kt",
],
static_libs: [
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt
new file mode 100644
index 000000000000..509f022310d0
--- /dev/null
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.plugins
+
+// TODO(b/265360975): Evaluate this plugin approach.
+/** Plugin to provide BC smartspace configuration */
+interface BcSmartspaceConfigPlugin {
+ /** Gets default date/weather disabled status. */
+ val isDefaultDateWeatherDisabled: Boolean
+}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 51f5baa8b45f..bc6e5ec6117c 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -94,6 +94,11 @@ public interface BcSmartspaceDataPlugin extends Plugin {
void registerDataProvider(BcSmartspaceDataPlugin plugin);
/**
+ * Sets {@link BcSmartspaceConfigPlugin}.
+ */
+ void registerConfigProvider(BcSmartspaceConfigPlugin configProvider);
+
+ /**
* Primary color for unprotected text
*/
void setPrimaryTextColor(int color);
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 d3fabaccb6d3..faf1b78c598d 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
@@ -21,6 +21,7 @@ import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.os.Looper
+import android.os.Trace
import android.provider.Settings
/**
@@ -51,14 +52,21 @@ class LogcatEchoTrackerDebug private constructor(private val contentResolver: Co
}
}
+ private fun clearCache() {
+ Trace.beginSection("LogcatEchoTrackerDebug#clearCache")
+ cachedBufferLevels.clear()
+ Trace.endSection()
+ }
+
private fun attach(mainLooper: Looper) {
+ Trace.beginSection("LogcatEchoTrackerDebug#attach")
contentResolver.registerContentObserver(
Settings.Global.getUriFor(BUFFER_PATH),
true,
object : ContentObserver(Handler(mainLooper)) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
super.onChange(selfChange, uri)
- cachedBufferLevels.clear()
+ clearCache()
}
}
)
@@ -69,10 +77,11 @@ class LogcatEchoTrackerDebug private constructor(private val contentResolver: Co
object : ContentObserver(Handler(mainLooper)) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
super.onChange(selfChange, uri)
- cachedTagLevels.clear()
+ clearCache()
}
}
)
+ Trace.endSection()
}
/** Whether [bufferName] should echo messages of [level] or higher to logcat. */
@@ -97,9 +106,12 @@ class LogcatEchoTrackerDebug private constructor(private val contentResolver: Co
private fun readSetting(path: String): LogLevel {
return try {
+ Trace.beginSection("LogcatEchoTrackerDebug#readSetting")
parseProp(Settings.Global.getString(contentResolver, path))
} catch (_: Settings.SettingNotFoundException) {
DEFAULT_LEVEL
+ } finally {
+ Trace.endSection()
}
}
diff --git a/packages/SystemUI/res-product/values-de/strings.xml b/packages/SystemUI/res-product/values-de/strings.xml
index b8d1a7ce5fe8..c82c7390e52e 100644
--- a/packages/SystemUI/res-product/values-de/strings.xml
+++ b/packages/SystemUI/res-product/values-de/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Entsperre dein Smartphone für weitere Optionen"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Entsperre dein Tablet für weitere Optionen"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Entsperre dein Gerät für weitere Optionen"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Wird auf diesem Smartphone abgespielt"</string>
- <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Wird auf diesem Tablet abgespielt"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Wiedergabe läuft auf diesem Smartphone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Wiedergabe läuft auf diesem Tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fr/strings.xml b/packages/SystemUI/res-product/values-fr/strings.xml
index a07c8d8908a8..75a08628522b 100644
--- a/packages/SystemUI/res-product/values-fr/strings.xml
+++ b/packages/SystemUI/res-product/values-fr/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Déverrouillez votre téléphone pour obtenir plus d\'options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Déverrouillez votre tablette pour obtenir plus d\'options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Déverrouillez votre appareil pour obtenir plus d\'options"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Lecture sur ce téléphone…"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Lecture sur ce téléphone"</string>
<string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Lecture sur cette tablette…"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ka/strings.xml b/packages/SystemUI/res-product/values-ka/strings.xml
index 1b496ccddfb2..3474a7f8f67e 100644
--- a/packages/SystemUI/res-product/values-ka/strings.xml
+++ b/packages/SystemUI/res-product/values-ka/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტელეფონი"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტაბლეტი"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი მოწყობილობა"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"უკრავს ტელეფონზე"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"უკრავს ამ ტელეფონზე"</string>
<string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"უკრავს ამ ტაბლეტზე"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
index b287fd90f440..fed58e681606 100644
--- a/packages/SystemUI/res-product/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia aberta neste smartphone"</string>
- <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia aberta neste tablet"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia tocando neste smartphone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia tocando neste tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml
index b287fd90f440..fed58e681606 100644
--- a/packages/SystemUI/res-product/values-pt/strings.xml
+++ b/packages/SystemUI/res-product/values-pt/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia aberta neste smartphone"</string>
- <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia aberta neste tablet"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Mídia tocando neste smartphone"</string>
+ <string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Mídia tocando neste tablet"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml
index bf8d94a63351..58309ff3471d 100644
--- a/packages/SystemUI/res-product/values-uz/strings.xml
+++ b/packages/SystemUI/res-product/values-uz/strings.xml
@@ -43,6 +43,6 @@
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Boshqa parametrlar uchun telefoningiz qulfini oching"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Boshqa parametrlar uchun planshetingiz qulfini oching"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Boshqa parametrlar uchun qurilmangiz qulfini oching"</string>
- <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Bu telefonda ijro etilmoqda"</string>
+ <string name="media_transfer_playing_this_device" product="default" msgid="5795784619523545556">"Bu telefonda ijro qilinmoqda"</string>
<string name="media_transfer_playing_this_device" product="tablet" msgid="222514408550408633">"Bu planshetda ijro etilmoqda"</string>
</resources>
diff --git a/packages/SystemUI/res/drawable/ic_camera.xml b/packages/SystemUI/res/drawable/ic_camera.xml
new file mode 100644
index 000000000000..ef1406c1c58a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_camera.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,42Q5.8,42 4.9,41.1Q4,40.2 4,39V13.35Q4,12.15 4.9,11.25Q5.8,10.35 7,10.35H14.35L18,6H30L33.65,10.35H41Q42.2,10.35 43.1,11.25Q44,12.15 44,13.35V39Q44,40.2 43.1,41.1Q42.2,42 41,42ZM7,39H41Q41,39 41,39Q41,39 41,39V13.35Q41,13.35 41,13.35Q41,13.35 41,13.35H7Q7,13.35 7,13.35Q7,13.35 7,13.35V39Q7,39 7,39Q7,39 7,39ZM7,39Q7,39 7,39Q7,39 7,39V13.35Q7,13.35 7,13.35Q7,13.35 7,13.35Q7,13.35 7,13.35Q7,13.35 7,13.35V39Q7,39 7,39Q7,39 7,39ZM24,34.7Q27.5,34.7 30,32.225Q32.5,29.75 32.5,26.2Q32.5,22.7 30,20.2Q27.5,17.7 24,17.7Q20.45,17.7 17.975,20.2Q15.5,22.7 15.5,26.2Q15.5,29.75 17.975,32.225Q20.45,34.7 24,34.7ZM24,26.2Q24,26.2 24,26.2Q24,26.2 24,26.2Q24,26.2 24,26.2Q24,26.2 24,26.2Q24,26.2 24,26.2Q24,26.2 24,26.2Q24,26.2 24,26.2Q24,26.2 24,26.2Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml b/packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml
new file mode 100644
index 000000000000..ee8d488343c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_note_task_shortcut_keyguard.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <path
+ android:fillAlpha="1"
+ android:fillColor="@android:color/white"
+ android:fillType="nonZero"
+ android:pathData="M17.6258,4.96L19.0358,6.37L7.4058,18.01L5.9958,16.6L17.6258,4.96ZM16.1358,3.62L4.1258,15.63L3.0158,19.83C2.9058,20.45 3.3858,21 3.9958,21C4.0558,21 4.1058,21 4.1658,20.99L8.3658,19.88L20.3758,7.86C20.7758,7.46 20.9958,6.93 20.9958,6.37C20.9958,5.81 20.7758,5.28 20.3758,4.88L19.1058,3.61C18.7158,3.22 18.1858,3 17.6258,3C17.0658,3 16.5358,3.22 16.1358,3.62Z" />
+ <path
+ android:fillAlpha="1"
+ android:fillColor="@android:color/white"
+ android:fillType="nonZero"
+ android:pathData="M20.1936,15.3369C20.3748,16.3837 19.9151,17.5414 18.8846,18.7597C19.1546,18.872 19.4576,18.9452 19.7724,18.9867C20.0839,19.0278 20.3683,19.0325 20.5749,19.0266C20.6772,19.0236 20.7578,19.0181 20.8101,19.0138C20.8362,19.0116 20.855,19.0097 20.8657,19.0085L20.8754,19.0074L20.875,19.0075C21.4217,18.9385 21.9214,19.325 21.9918,19.8718C22.0624,20.4195 21.6756,20.9208 21.1279,20.9914L21,19.9996C21.1279,20.9914 21.1265,20.9916 21.1265,20.9916L21.1249,20.9918L21.1211,20.9923L21.1107,20.9935L21.0795,20.997C21.0542,20.9998 21.0199,21.0032 20.9775,21.0067C20.8929,21.0138 20.7753,21.0216 20.6323,21.0257C20.3481,21.0339 19.9533,21.0279 19.5109,20.9695C18.873,20.8854 18.0393,20.6793 17.3106,20.1662C16.9605,20.3559 16.5876,20.4952 16.2299,20.6003C15.5742,20.7927 14.8754,20.8968 14.2534,20.9534C13.6801,21.0055 13.4553,21.0037 13.1015,21.0008C13.0689,21.0005 13.0352,21.0002 13,21H12.8594C12.8214,21.0002 12.785,21.0006 12.7504,21.0009C12.6524,21.0019 12.5683,21.0027 12.5,21H12.0562C12.0277,21.0003 12.0054,21.0006 11.9926,21.001L11.9751,21H9L11,19H11.9795C11.9929,18.9997 12.0064,18.9997 12.0199,19H12.4117C12.4534,18.9996 12.4864,18.9995 12.5,19H12.9675C12.977,18.9999 12.9878,18.9999 13,19C13.0446,19.0003 13.0859,19.0007 13.1249,19.0011C13.4259,19.0038 13.591,19.0054 14.0723,18.9616C14.6201,18.9118 15.1795,18.8242 15.6665,18.6813C15.753,18.6559 15.8346,18.6295 15.9114,18.6022C15.0315,17.2981 14.7125,16.1044 15.015,15.0829C15.4095,13.7511 16.6784,13.2418 17.7026,13.2864C18.7262,13.3309 19.954,13.9529 20.1936,15.3369ZM16.9327,15.6508C16.873,15.8523 16.8651,16.3878 17.4697,17.334C18.2007,16.4284 18.2585,15.8839 18.2229,15.6781C18.1939,15.5108 18.0297,15.3025 17.6157,15.2845C17.2025,15.2665 16.9885,15.4626 16.9327,15.6508Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_note_task_button.xml b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget.xml
index bb5e224ea315..759018289562 100644
--- a/packages/SystemUI/res/drawable/ic_note_task_button.xml
+++ b/packages/SystemUI/res/drawable/ic_note_task_shortcut_widget.xml
@@ -19,10 +19,13 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
+ android:fillAlpha="1"
android:fillColor="#636C6F"
+ android:fillType="nonZero"
android:pathData="M17.6258,4.96L19.0358,6.37L7.4058,18.01L5.9958,16.6L17.6258,4.96ZM16.1358,3.62L4.1258,15.63L3.0158,19.83C2.9058,20.45 3.3858,21 3.9958,21C4.0558,21 4.1058,21 4.1658,20.99L8.3658,19.88L20.3758,7.86C20.7758,7.46 20.9958,6.93 20.9958,6.37C20.9958,5.81 20.7758,5.28 20.3758,4.88L19.1058,3.61C18.7158,3.22 18.1858,3 17.6258,3C17.0658,3 16.5358,3.22 16.1358,3.62Z" />
<path
+ android:fillAlpha="1"
android:fillColor="#636C6F"
- android:fillType="evenOdd"
+ android:fillType="nonZero"
android:pathData="M20.1936,15.3369C20.3748,16.3837 19.9151,17.5414 18.8846,18.7597C19.1546,18.872 19.4576,18.9452 19.7724,18.9867C20.0839,19.0278 20.3683,19.0325 20.5749,19.0266C20.6772,19.0236 20.7578,19.0181 20.8101,19.0138C20.8362,19.0116 20.855,19.0097 20.8657,19.0085L20.8754,19.0074L20.875,19.0075C21.4217,18.9385 21.9214,19.325 21.9918,19.8718C22.0624,20.4195 21.6756,20.9208 21.1279,20.9914L21,19.9996C21.1279,20.9914 21.1265,20.9916 21.1265,20.9916L21.1249,20.9918L21.1211,20.9923L21.1107,20.9935L21.0795,20.997C21.0542,20.9998 21.0199,21.0032 20.9775,21.0067C20.8929,21.0138 20.7753,21.0216 20.6323,21.0257C20.3481,21.0339 19.9533,21.0279 19.5109,20.9695C18.873,20.8854 18.0393,20.6793 17.3106,20.1662C16.9605,20.3559 16.5876,20.4952 16.2299,20.6003C15.5742,20.7927 14.8754,20.8968 14.2534,20.9534C13.6801,21.0055 13.4553,21.0037 13.1015,21.0008C13.0689,21.0005 13.0352,21.0002 13,21H12.8594C12.8214,21.0002 12.785,21.0006 12.7504,21.0009C12.6524,21.0019 12.5683,21.0027 12.5,21H12.0562C12.0277,21.0003 12.0054,21.0006 11.9926,21.001L11.9751,21H9L11,19H11.9795C11.9929,18.9997 12.0064,18.9997 12.0199,19H12.4117C12.4534,18.9996 12.4864,18.9995 12.5,19H12.9675C12.977,18.9999 12.9878,18.9999 13,19C13.0446,19.0003 13.0859,19.0007 13.1249,19.0011C13.4259,19.0038 13.591,19.0054 14.0723,18.9616C14.6201,18.9118 15.1795,18.8242 15.6665,18.6813C15.753,18.6559 15.8346,18.6295 15.9114,18.6022C15.0315,17.2981 14.7125,16.1044 15.015,15.0829C15.4095,13.7511 16.6784,13.2418 17.7026,13.2864C18.7262,13.3309 19.954,13.9529 20.1936,15.3369ZM16.9327,15.6508C16.873,15.8523 16.8651,16.3878 17.4697,17.334C18.2007,16.4284 18.2585,15.8839 18.2229,15.6781C18.1939,15.5108 18.0297,15.3025 17.6157,15.2845C17.2025,15.2665 16.9885,15.4626 16.9327,15.6508Z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_videocam.xml b/packages/SystemUI/res/drawable/ic_videocam.xml
new file mode 100644
index 000000000000..de2bc7bccdf1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_videocam.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M7,40Q5.8,40 4.9,39.1Q4,38.2 4,37V11Q4,9.8 4.9,8.9Q5.8,8 7,8H33Q34.2,8 35.1,8.9Q36,9.8 36,11V21.75L44,13.75V34.25L36,26.25V37Q36,38.2 35.1,39.1Q34.2,40 33,40ZM7,37H33Q33,37 33,37Q33,37 33,37V11Q33,11 33,11Q33,11 33,11H7Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37ZM7,37Q7,37 7,37Q7,37 7,37V11Q7,11 7,11Q7,11 7,11Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
index 18fcebbb65a0..87b5a4c2fc5b 100644
--- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
@@ -16,53 +16,13 @@
* limitations under the License.
*/
-->
-<selector
+<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-
- <item android:state_selected="true">
- <layer-list>
- <item
- android:left="3dp"
- android:top="3dp"
- android:right="3dp"
- android:bottom="3dp">
- <shape android:shape="oval">
- <solid android:color="?androidprv:attr/colorSurface"/>
- <size
- android:width="@dimen/keyguard_affordance_width"
- android:height="@dimen/keyguard_affordance_height"/>
- </shape>
- </item>
-
- <item>
- <shape android:shape="oval">
- <stroke
- android:color="@color/control_primary_text"
- android:width="2dp"/>
- <size
- android:width="@dimen/keyguard_affordance_width"
- android:height="@dimen/keyguard_affordance_height"/>
- </shape>
- </item>
- </layer-list>
- </item>
-
- <item>
- <layer-list>
- <item
- android:left="3dp"
- android:top="3dp"
- android:right="3dp"
- android:bottom="3dp">
- <shape android:shape="oval">
- <solid android:color="?androidprv:attr/colorSurface"/>
- <size
- android:width="@dimen/keyguard_affordance_width"
- android:height="@dimen/keyguard_affordance_height"/>
- </shape>
- </item>
- </layer-list>
- </item>
-
-</selector>
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ <size
+ android:width="@dimen/keyguard_affordance_fixed_width"
+ android:height="@dimen/keyguard_affordance_fixed_height"/>
+ <corners android:radius="@dimen/keyguard_affordance_fixed_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_selected_border.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_selected_border.xml
new file mode 100644
index 000000000000..acd2462dbf78
--- /dev/null
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_selected_border.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2023, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_selected="true">
+ <shape android:shape="oval">
+ <stroke
+ android:color="@color/control_primary_text"
+ android:width="2dp"/>
+ <size
+ android:width="@dimen/keyguard_affordance_fixed_width"
+ android:height="@dimen/keyguard_affordance_fixed_height"/>
+ </shape>
+ </item>
+</selector>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 6120863f23ab..3f955154c875 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -67,6 +67,7 @@
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
@@ -79,6 +80,7 @@
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index b76de5afdb73..e182a6ae78de 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,6 +24,7 @@
android:orientation="vertical">
<LinearLayout
+ android:id="@+id/media_metadata_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start|center_vertical"
diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
index 21d12c278453..4483db8aeb6f 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
@@ -27,6 +27,14 @@
android:layout_height="wrap_content"
/>
+ <com.android.systemui.media.taptotransfer.receiver.ReceiverChipRippleView
+ android:id="@+id/icon_glow_ripple"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <!-- Add a bottom margin to avoid the glow of the icon ripple from being cropped by screen
+ bounds while animating with the icon -->
<com.android.internal.widget.CachingIconView
android:id="@+id/app_icon"
android:background="@drawable/media_ttt_chip_background_receiver"
@@ -34,6 +42,7 @@
android:layout_height="@dimen/media_ttt_icon_size_receiver"
android:layout_gravity="center|bottom"
android:alpha="0.0"
+ android:layout_marginBottom="@dimen/media_ttt_receiver_icon_bottom_margin"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 5aa608084510..d1a2cf4c24b2 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -25,6 +25,7 @@
android:focusable="true"
android:clipChildren="false"
android:clipToPadding="false"
+ android:paddingStart="8dp"
>
<LinearLayout
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index bbb8df1c5a4a..db94c92738f2 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -26,6 +26,17 @@
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/unlock_prompt_footer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center"
+ android:drawablePadding="8dp"
+ android:visibility="gone"
+ android:textAppearance="?android:attr/textAppearanceButton"
+ android:text="@string/unlock_to_see_notif_text"/>
<com.android.systemui.statusbar.notification.row.FooterViewButton
style="@style/TextAppearance.NotificationSectionHeaderButton"
android:id="@+id/manage_text"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c0509a9f7702..fbe6280f71bd 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ondergrens <xliff:g id="PERCENT">%1$d</xliff:g> persent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Linkergrens <xliff:g id="PERCENT">%1$d</xliff:g> persent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Regtergrens <xliff:g id="PERCENT">%1$d</xliff:g> persent"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Werkskermskote word in die <xliff:g id="APP">%1$s</xliff:g>-app gestoor"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Lêers"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skermopnemer"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Verwerk tans skermopname"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Deurlopende kennisgewing vir \'n skermopnamesessie"</string>
@@ -373,11 +375,11 @@
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Begin opneem of uitsaai met <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Laat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toe om te deel of op te neem?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Hele skerm"</string>
- <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"’n Enkele program"</string>
+ <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"’n Enkele app"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Wanneer jy deel, opneem of uitsaai, het <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot enigiets wat op jou skerm sigbaar is of op jou toestel gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
<string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Wanneer jy ’n program deel, opneem of uitsaai, het <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot enigiets wat in daardie program sigbaar is of daarin gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Gaan voort"</string>
- <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Deel of neem ’n program op"</string>
+ <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Deel of neem ’n app op"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Laat hierdie app toe om te deel of op te neem?"</string>
<string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Wanneer jy deel, opneem of uitsaai, het hierdie app toegang tot enigiets wat op jou skerm sigbaar is of op jou toestel gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
<string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Wanneer jy ’n app deel, opneem of uitsaai, het hierdie app toegang tot enigiets wat in daardie program sigbaar is of daarin gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Speel <xliff:g id="SONG_NAME">%1$s</xliff:g> vanaf <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Ontdoen"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Beweeg nader om op <xliff:g id="DEVICENAME">%1$s</xliff:g> te speel"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Beweeg nader aan <xliff:g id="DEVICENAME">%1$s</xliff:g> om hier te speel"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Iets is fout. Probeer weer."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Laai tans"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Luidsprekers en skerms"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Voorgestelde toestelle"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitsaai werk"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Saai uit"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mense in jou omtrek met versoenbare Bluetooth-toestelle kan na die media luister wat jy uitsaai"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Hierdie skerm sal afskakel"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Voubare toestel word ontvou"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Voubare toestel word omgekeer"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stilus se battery is amper pap"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d0c5c9040ea8..0a26c1d4354c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"የታች ወሰን <xliff:g id="PERCENT">%1$d</xliff:g> በመቶ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"የግራ ወሰን <xliff:g id="PERCENT">%1$d</xliff:g> በመቶ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"የቀኝ ወሰን <xliff:g id="PERCENT">%1$d</xliff:g> በመቶ"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"የማያ መቅጃ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገጽ ቀረጻን በማሰናዳት ላይ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገጽ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ከ<xliff:g id="APP_LABEL">%2$s</xliff:g> ያጫውቱ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ቀልብስ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ ለማጫወት ጠጋ ያድርጉ"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"እዚህ ለመጫወት ወደ <xliff:g id="DEVICENAME">%1$s</xliff:g> ቀረብ ይበሉ"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"የሆነ ችግር ተፈጥሯል። እንደገና ይሞክሩ።"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"በመጫን ላይ"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"የድምጽ መጠን"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ድምጽ ማውጫዎች እና ማሳያዎች"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ማሰራጨት እንዴት እንደሚሠራ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ስርጭት"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ተኳሃኝ የብሉቱዝ መሣሪያዎች ያላቸው በአቅራቢያዎ ያሉ ሰዎች እርስዎ እያሰራጩት ያሉትን ሚዲያ ማዳመጥ ይችላሉ"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ይህ ማያ ገጽ ይጠፋል"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"መታጠፍ የሚችል መሣሪያ እየተዘረጋ ነው"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"መታጠፍ የሚችል መሣሪያ እየተገለበጠ ነው"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"የብሮስፌ ባትሪ ዝቅተኛ ነው"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ea5bce12b3db..d641887c6153 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"الحد السفلى <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"الحد الأيسر <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"الحد الأيمن <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"مسجّل الشاشة"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
@@ -371,7 +375,7 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"ستتمكن الخدمة التي تقدّم هذه الوظيفة من الوصول إلى كل المعلومات المرئية لك على الشاشة أو التي يتم تشغيلها على جهازك أثناء التسجيل أو البث. ويشمل ذلك معلومات مثل كلمات المرور وتفاصيل الدفع والصور والرسائل والمقاطع الصوتية التي تشغِّلها."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"هل تريد بدء التسجيل أو البث؟"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"هل تريد بدء التسجيل أو الإرسال باستخدام <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>؟"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"هل تريد السماح لتطبيق <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>بالمشاركة أو التسجيل؟"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"هل تريد السماح لتطبيق <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> بالمشاركة أو التسجيل؟"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"الشاشة بالكامل"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"تطبيق واحد"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"أثناء المشاركة أو التسجيل أو البث، يمكن لتطبيق <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> الوصول إلى كل العناصر المرئية على شاشتك أو التي يتم تشغيلها على جهازك، لذا يُرجى توخي الحذر بشأن كلمات المرور أو تفاصيل الدفع أو الرسائل أو المعلومات الحساسة الأخرى."</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"تراجع"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"عليك الاقتراب لتشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"يُرجى الاقتراب من <xliff:g id="DEVICENAME">%1$s</xliff:g> لتشغيل الوسائط هنا."</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"جارٍ تشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"حدث خطأ. يُرجى إعادة المحاولة."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"جارٍ التحميل"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"مستوى الصوت"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"مكبّرات الصوت والشاشات"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"كيفية عمل البث"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"البث"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"يمكن للأشخاص القريبين منك الذين لديهم أجهزة متوافقة تتضمّن بلوتوث الاستماع إلى الوسائط التي تبثها."</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* سيتم إطفاء هذه الشاشة."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"جهاز قابل للطي يجري فتحه"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"جهاز قابل للطي يجري قلبه"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"بطارية قلم الشاشة منخفضة"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index cbd2bedd3f20..e376a6c14bbb 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"তলৰ সীমা <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"বাওঁফালৰ সীমা <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"সোঁফালৰ সীমা <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্ৰীন ৰেকৰ্ডাৰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রীন ৰেকৰ্ডিঙৰ প্ৰক্ৰিয়াকৰণ হৈ আছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রীন ৰেকৰ্ডিং ছেশ্বন চলি থকা সময়ত পোৱা জাননী"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ত <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ কৰক"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"আনডু কৰক"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে’ কৰিবলৈ ওচৰলৈ যাওক"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ইয়াত খেলিবলৈ <xliff:g id="DEVICENAME">%1$s</xliff:g>ৰ আৰু ওচৰলৈ যাওক"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে কৰি থকা হৈছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ল’ড হৈ আছে"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্‌টো পৰীক্ষা কৰক"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ভলিউম"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পীকাৰ আৰু ডিছপ্লে’"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"সম্প্ৰচাৰ কৰাটোৱে কেনেকৈ কাম কৰে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্ৰচাৰ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"সমিল ব্লুটুথ ডিভাইচৰ সৈতে আপোনাৰ নিকটৱৰ্তী স্থানত থকা লোকসকলে আপুনি সম্প্ৰচাৰ কৰা মিডিয়াটো শুনিব পাৰে"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ই স্ক্ৰীনখন অফ হ’ব"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"ষ্টাইলাছৰ বেটাৰী কম আছে"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index dd4d5109855d..a2f20cea73fc 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Aşağı sərhəd <xliff:g id="PERCENT">%1$d</xliff:g> faiz"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Sol sərhəd <xliff:g id="PERCENT">%1$d</xliff:g> faiz"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Sağ sərhəd <xliff:g id="PERCENT">%1$d</xliff:g> faiz"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Yazıcısı"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran çəkilişi emal edilir"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekranın video çəkimi ərzində silinməyən bildiriş"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> mahnısını <xliff:g id="APP_LABEL">%2$s</xliff:g> tətbiqindən oxudun"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Geri qaytarın"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxutmaq üçün yaxınlaşın"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oxutmaq üçün <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaxınlaşın"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Xəta oldu. Yenə cəhd edin."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Yüklənir"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Səs"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Dinamiklər &amp; Displeylər"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayım necə işləyir"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Yayım"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Uyğun Bluetooth cihazları olan yaxınlığınızdakı insanlar yayımladığınız medianı dinləyə bilər"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Bu ekran deaktiv ediləcək"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Qatlana bilən cihaz açılır"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Qatlana bilən cihaz fırladılır"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Qələm enerjisi azdır"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 64313896a4ce..19209870ac4d 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Donja ivica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Leva ivica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Desna ivica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Opozovi"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite da biste puštali muziku na: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu puštali"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Pušta se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo je do greške. Probajte ponovo."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Učitava se"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Zvuk"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i ekrani"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcioniše emitovanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitovanje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ljudi u blizini sa kompatibilnim Bluetooth uređajima mogu da slušaju medijski sadržaj koji emitujete"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ovaj ekran će se isključiti"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Uređaj na preklop se otvara"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Uređaj na preklop se obrće"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Nizak nivo baterije pisaljke"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 7e7262a057d3..537622e07e2a 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ніжняя граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Левая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Правая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Запіс экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Апрацоўваецца запіс экрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Прайграйце кампазіцыю \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" з дапамогай праграмы \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Адрабіць"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Каб прайграць мультымедыя на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", наблізьцеся да яе"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Падыдзіце бліжэй да прылады \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", каб прайграць на гэтай"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешта пайшло не так. Паўтарыце спробу."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Ідзе загрузка"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Гучнасць"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Дынамікі і дысплэі"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як адбываецца трансляцыя"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляцыя"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Людзі паблізу, у якіх ёсць прылады з Bluetooth, змогуць праслухваць мультымедыйнае змесціва, якое вы трансліруеце"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Гэты экран будзе выключаны"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складная прылада ў раскладзеным выглядзе"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перавернутая складная прылада"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Нізкі ўзровень зараду пяра"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 26a154fadc56..eba0d0333033 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Долна граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Лява граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Дясна граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Запис на екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
@@ -375,12 +379,12 @@
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Цял екран"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Едно приложение"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Когато споделяте, записвате или предавате, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има достъп до всичко, което се вижда на екрана ви или се възпроизвежда на устройството ви, затова бъдете внимателни с пароли, подробности за начини на плащане, съобщения или друга поверителна информация."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Когато споделяте, записвате или предавате, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има достъп до всичко, което се показва или възпроизвежда в това приложение, затова бъдете внимателни с пароли, подробности за начини на плащане, съобщения или друга поверителна информация."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Когато споделяте, записвате или предавате приложение, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има достъп до всичко, което се показва или възпроизвежда в това приложение, затова бъдете внимателни с пароли, подробности за начини на плащане, съобщения или друга поверителна информация."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Напред"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Споделяне или записване на приложение"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Да се разреши ли на това приложение да споделя или записва?"</string>
<string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Когато споделяте, записвате или предавате, това приложение има достъп до всичко, което се вижда на екрана ви или се възпроизвежда на устройството ви, затова бъдете внимателни с пароли, подробности за начини на плащане, съобщения или друга поверителна информация."</string>
- <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Когато споделяте, записвате или предавате, това приложение има достъп до всичко, което се показва или възпроизвежда в него, затова бъдете внимателни с пароли, подробности за начини на плащане, съобщения или друга поверителна информация."</string>
+ <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Когато споделяте, записвате или предавате приложение, това приложение има достъп до всичко, което се показва или възпроизвежда в приложението, затова бъдете внимателни с пароли, подробности за начини на плащане, съобщения или друга поверителна информация."</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Блокирано от системния ви администратор"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Заснемането на екрана е деактивирано от правило за устройството"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Изчистване на всички"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пускане на <xliff:g id="SONG_NAME">%1$s</xliff:g> от <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Отмяна"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Преместете се по-близо, за да се възпроизведе на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за възпроизвеждане на това устройство"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нещо се обърка. Опитайте отново."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Зарежда се"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Сила на звука"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Високоговорители и екрани"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работи предаването"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Предаване"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Хората в близост със съвместими устройства с Bluetooth могат да слушат мултимедията, която предавате"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Този екран ще се изключи"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Разгъване на сгъваемо устройство"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Обръщане на сгъваемо устройство"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Батерията на писалката е изтощена"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index b6069a4a9361..13353aa1a0be 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"নিচের প্রান্ত থেকে <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"বাঁ প্রান্ত থেকে <xliff:g id="PERCENT">%1$d</xliff:g> শতাংশ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ডান প্রান্ত থেকে <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"অফিসের স্ক্রিনশট <xliff:g id="APP">%1$s</xliff:g> অ্যাপে সেভ করা হয়"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ফাইল"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্রিন রেকর্ডার"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%2$s</xliff:g> অ্যাপে চালান"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"আগের অবস্থায় ফিরুন"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ চালাতে আরও কাছে আনুন"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"এখান থেকে চালাতে <xliff:g id="DEVICENAME">%1$s</xliff:g>-এর কাছে নিয়ে যান"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"লোড করা হচ্ছে"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ট্যাবলেট"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ভলিউম"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পিকার &amp; ডিসপ্লে"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"সাজেস্ট করা ডিভাইস"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ব্রডকাস্ট কীভাবে কাজ করে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্রচার করুন"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"আশপাশে লোকজন যাদের মানানসই ব্লুটুথ ডিভাইস আছে, তারা আপনার ব্রডকাস্ট করা মিডিয়া শুনতে পারবেন"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ এই স্ক্রিন বন্ধ হয়ে যাবে"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ফোল্ড করা যায় এমন ডিভাইস খোলা হচ্ছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ফোল্ড করা যায় এমন ডিভাইস উল্টানো হচ্ছে"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"স্টাইলাস ব্যাটারিতে চার্জ কম আছে"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 67efa7570e4f..2475a477c15d 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Donja granica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Lijeva granica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Desna granica <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Poslovni snimci ekrana se pohranjuju u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fajlovi"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
@@ -849,12 +851,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite se da reproducirate na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da na njemu reproducirate"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite da reproducirate na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije uredu. Pokušajte ponovo."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Učitavanje"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Jačina zvuka"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i ekrani"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcionira emitiranje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitirajte"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u vašoj blizini s kompatibilnim Bluetooth uređajima mogu slušati medijske sadržaje koje emitirate"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ekran će se isključiti"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Sklopivi uređaj se rasklapa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Sklopivi uređaj se obrće"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Baterija pisaljke je slaba"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2f48676a142a..ef732184a9f6 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Marge inferior <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Marge esquerre <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Marge dret <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Gravació de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
@@ -98,7 +102,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"Durant la gravació, el sistema Android pot capturar qualsevol informació sensible que es mostri a la pantalla o que es reprodueixi al dispositiu. Això inclou contrasenyes, informació de pagament, fotos, missatges i àudio."</string>
<string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Grava la pantalla completa"</string>
<string name="screenrecord_option_single_app" msgid="5954863081500035825">"Grava una sola aplicació"</string>
- <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Mentre graves, Android té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi al dispositiu. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges o altra informació sensible."</string>
+ <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Mentre graves contingut, Android pot accedir a tot el que es veu a la pantalla o que es reprodueix al dispositiu. Per això cal que vagis amb compte amb les contrasenyes, les dades de pagament, els missatges o qualsevol altra informació sensible."</string>
<string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Mentre graves una aplicació, Android té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi a l\'aplicació. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges o altra informació sensible."</string>
<string name="screenrecord_start_recording" msgid="348286842544768740">"Inicia la gravació"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Grava l\'àudio"</string>
@@ -371,11 +375,11 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació visible a la teva pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio que reprodueixis."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vols començar a gravar o emetre contingut?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Vols començar a gravar o emetre contingut amb <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Vols permetre que <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comparteixi o gravi?"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Vols permetre que <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comparteixi o gravi contingut?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Tota la pantalla"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Una sola aplicació"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Quan estàs compartint, gravant o emetent, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi al dispositiu. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges o altra informació sensible."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quan estàs compartint, gravant o emetent, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi a l\'aplicació. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges o altra informació sensible."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Mentre comparteixes, graves o emets contingut, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> pot accedir a tot el que es veu a la pantalla o que es reprodueix a l\'aplicació. Per això cal que vagis amb compte amb les contrasenyes, les dades de pagament, els missatges o qualsevol altra informació sensible."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continua"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Comparteix o grava una aplicació"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Vols permetre que aquesta aplicació comparteixi o gravi contingut?"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reprodueix <xliff:g id="SONG_NAME">%1$s</xliff:g> des de l\'aplicació <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfés"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Mou més a prop per reproduir a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acosta\'t a <xliff:g id="DEVICENAME">%1$s</xliff:g> per reproduir el contingut aquí"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"S\'ha produït un error. Torna-ho a provar."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"S\'està carregant"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altaveus i pantalles"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Com funciona l\'emissió"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emet"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les persones properes amb dispositius Bluetooth compatibles poden escoltar el contingut multimèdia que emets"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Aquesta pantalla s\'apagarà"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositiu plegable desplegant-se"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositiu plegable girant"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria del llapis òptic baixa"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index feeaa32f68a7..3c8c6da4ff5c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Dolní okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Levý okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Pravý okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Přehrát skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikace <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Vrátit zpět"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Pokud chcete přehrávat na zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>, přibližte se k němu"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pokud zde chcete přehrávat média, přibližte se k zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Přehrávání v zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Došlo k chybě. Zkuste to znovu."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Načítání"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hlasitost"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Reproduktory a displeje"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak vysílání funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysílání"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lidé ve vašem okolí s kompatibilními zařízeními Bluetooth mohou poslouchat média, která vysíláte"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Tato obrazovka se vypne"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozkládání rozkládacího zařízení"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Otáčení rozkládacího zařízení"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Slabá baterie dotykového pera"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index f64587e26731..585d85838e81 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Nederste kant: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Venstre kant: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Højre kant: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skærmoptagelse"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skærmoptagelse"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Fortryd"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flyt enheden tættere på for at afspille på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ryk tættere på <xliff:g id="DEVICENAME">%1$s</xliff:g> for at afspille her"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ryk tættere på for at afspille på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noget gik galt. Prøv igen."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Indlæser"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Lydstyrke"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Højttalere og skærme"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Sådan fungerer udsendelser"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Udsendelse"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i nærheden, som har kompatible Bluetooth-enheder, kan lytte til det medie, du udsender"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ *Denne skærm slukkes"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldbar enhed foldes ud"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldbar enhed vendes om"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Lavt batteriniveau på styluspen"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index bd4c5872dfce..078c02d2b259 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Unterer Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Linker Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Rechter Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
@@ -98,8 +102,8 @@
<string name="screenrecord_description" msgid="1123231719680353736">"Beim Aufnehmen kann das Android-System vertrauliche Informationen erfassen, die auf deinem Bildschirm angezeigt oder von deinem Gerät wiedergegeben werden. Das können Passwörter, Zahlungsinformationen, Fotos, Nachrichten und Audioinhalte sein."</string>
<string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Gesamten Bildschirm aufnehmen"</string>
<string name="screenrecord_option_single_app" msgid="5954863081500035825">"Eine einzelne App aufnehmen"</string>
- <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Während der Aufnahme hat Android Zugriff auf alle Inhalte, die auf dem Bildschirm sichtbar sind oder auf dem Gerät wiedergegeben werden. Sei daher mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen vorsichtig."</string>
- <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Während der Aufnahme einer App hat Android Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder wiedergegeben werden. Sei daher mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen vorsichtig."</string>
+ <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Während der Aufnahme hat Android Zugriff auf alle Inhalte, die auf dem Bildschirm sichtbar sind oder auf dem Gerät wiedergegeben werden. Sei daher vorsichtig mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen."</string>
+ <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Während der Aufnahme einer App hat Android Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder wiedergegeben werden. Sei daher vorsichtig mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen."</string>
<string name="screenrecord_start_recording" msgid="348286842544768740">"Aufnahme starten"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Audio aufnehmen"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio des Geräts"</string>
@@ -374,13 +378,13 @@
<string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Zulassen, dass <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Inhalte teilt oder aufnimmt?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Gesamter Bildschirm"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Eine einzelne App"</string>
- <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Beim Teilen, Aufnehmen oder Übertragen hat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Zugriff auf alle Inhalte, die auf dem Bildschirm sichtbar sind oder auf dem Gerät wiedergegeben werden. Sei daher mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen vorsichtig."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Beim Teilen, Aufnehmen oder Übertragen einer App hat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder wiedergegeben werden. Sei daher mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen vorsichtig."</string>
+ <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Beim Teilen, Aufnehmen oder Übertragen hat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Zugriff auf alle Inhalte, die auf dem Bildschirm sichtbar sind oder auf dem Gerät wiedergegeben werden. Sei daher vorsichtig mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Beim Teilen, Aufnehmen oder Übertragen einer App hat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder wiedergegeben werden. Sei daher vorsichtig mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Weiter"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"App teilen oder aufnehmen"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Dieser App das Teilen oder Aufnehmen erlauben?"</string>
- <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Beim Teilen, Aufnehmen oder Übertragen hat diese App Zugriff auf alle Inhalte, die auf dem Bildschirm sichtbar sind oder auf dem Gerät wiedergegeben werden. Sei daher mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen vorsichtig."</string>
- <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Beim Teilen, Aufnehmen oder Übertragen einer App hat diese App Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder wiedergegeben werden. Sei daher mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen vorsichtig."</string>
+ <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Beim Teilen, Aufnehmen oder Übertragen hat diese App Zugriff auf alle Inhalte, die auf dem Bildschirm sichtbar sind oder auf dem Gerät wiedergegeben werden. Sei daher vorsichtig mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen."</string>
+ <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Beim Teilen, Aufnehmen oder Übertragen einer App hat diese App Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder wiedergegeben werden. Sei daher vorsichtig mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen."</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Vom IT-Administrator blockiert"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Bildschirmaufnahme ist durch die Geräterichtlinien deaktiviert"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Alle löschen"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergeben"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> über <xliff:g id="APP_LABEL">%2$s</xliff:g> wiedergeben"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Rückgängig machen"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Gehe für die Wiedergabe näher an <xliff:g id="DEVICENAME">%1$s</xliff:g> heran"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Platziere für die Wiedergabe dein Gerät näher an „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Wird auf „<xliff:g id="DEVICENAME">%1$s</xliff:g>“ abgespielt"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Gehe für die Wiedergabe näher an „<xliff:g id="DEVICENAME">%1$s</xliff:g>“ heran"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Wiedergabe läuft auf „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Es gab ein Problem. Versuch es noch einmal."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Wird geladen"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Lautstärke"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Lautsprecher &amp; Displays"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Funktionsweise von Nachrichten an alle"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Nachricht an alle"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personen, die in der Nähe sind und kompatible Bluetooth-Geräten haben, können sich die Medien anhören, die du per Nachricht an alle sendest"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Dieses Display wird dann ausgeschaltet"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Faltbares Gerät wird geöffnet"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Faltbares Gerät wird umgeklappt"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus-Akkustand niedrig"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 05cf06cc4ba0..fce50e56cb30 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Κάτω όριο <xliff:g id="PERCENT">%1$d</xliff:g> τοις εκατό"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Αριστερό όριο <xliff:g id="PERCENT">%1$d</xliff:g> τοις εκατό"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Δεξί όριο <xliff:g id="PERCENT">%1$d</xliff:g> τοις εκατό"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Τα στιγμιότυπα οθόνης εργασίας αποθηκεύονται στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Αρχεία"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Εγγραφή οθόνης"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ειδοποίηση σε εξέλιξη για μια περίοδο λειτουργίας εγγραφής οθόνης"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Αναίρεση"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Πλησιάστε για αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Μετακινηθείτε πιο κοντά στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g> για αναπαραγωγή εδώ"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Φόρτωση"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ένταση ήχου"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Ηχεία και οθόνες"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Προτεινόμενες συσκευές"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Πώς λειτουργεί η μετάδοση"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Μετάδοση"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Οι άνθρωποι με συμβατές συσκευές Bluetooth που βρίσκονται κοντά σας μπορούν να ακούσουν το μέσο που μεταδίδετε."</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* Αυτή η οθόνη θα απενεργοποιηθεί"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Αναδιπλούμενη συσκευή που ξεδιπλώνει"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Αναδιπλούμενη συσκευή που διπλώνει"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Χαμηλή στάθμη μπαταρίας γραφίδας"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 7c902807860b..b0421c0818b2 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Work screenshots are saved in the <xliff:g id="APP">%1$s</xliff:g> app"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -850,10 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -877,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers &amp; displays"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -1014,5 +1019,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index f195c640bd41..5e564c365944 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Work screenshots are saved in the <xliff:g id="APP">%1$s</xliff:g> app"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -850,10 +852,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"To play here, move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -877,6 +880,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers &amp; Displays"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested Devices"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media you\'re broadcasting"</string>
@@ -1014,5 +1018,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 7c902807860b..b0421c0818b2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Work screenshots are saved in the <xliff:g id="APP">%1$s</xliff:g> app"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -850,10 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -877,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers &amp; displays"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -1014,5 +1019,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 7c902807860b..b0421c0818b2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Work screenshots are saved in the <xliff:g id="APP">%1$s</xliff:g> app"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -850,10 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -877,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers &amp; displays"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -1014,5 +1019,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stylus battery low"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> battery remaining"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connect your stylus to a charger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 03659b4f7c69..2ab012df6456 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‎‏‏‏‎‎Bottom boundary ‎‏‎‎‏‏‎<xliff:g id="PERCENT">%1$d</xliff:g>‎‏‎‎‏‏‏‎ percent‎‏‎‎‏‎"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‏‎‏‏‎‏‎Left boundary ‎‏‎‎‏‏‎<xliff:g id="PERCENT">%1$d</xliff:g>‎‏‎‎‏‏‏‎ percent‎‏‎‎‏‎"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎Right boundary ‎‏‎‎‏‏‎<xliff:g id="PERCENT">%1$d</xliff:g>‎‏‎‎‏‏‏‎ percent‎‏‎‎‏‎"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎Work screenshots are saved in the ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ app‎‏‎‎‏‎"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎Files‎‏‎‎‏‎"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎Screen Recorder‎‏‎‎‏‎"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎Processing screen recording‎‏‎‎‏‎"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎Ongoing notification for a screen record session‎‏‎‎‏‎"</string>
@@ -850,10 +852,11 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‎Play ‎‏‎‎‏‏‎<xliff:g id="SONG_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎<xliff:g id="APP_LABEL">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎Undo‎‏‎‎‏‎"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎‎‎Move closer to play on ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎Move closer to ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to play here‎‏‎‎‏‎"</string>
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎To play here, move closer to ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎Playing on ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎Something went wrong. Try again.‎‏‎‎‏‎"</string>
<string name="media_transfer_loading" msgid="5544017127027152422">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎Loading‎‏‎‎‏‎"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‎tablet‎‏‎‎‏‎"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎Inactive, check app‎‏‎‎‏‎"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Not found‎‏‎‎‏‎"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎Control is unavailable‎‏‎‎‏‎"</string>
@@ -877,6 +880,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎Volume‎‏‎‎‏‎"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%1$d</xliff:g>‎‏‎‎‏‏‏‎%%‎‏‎‎‏‎"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎Speakers &amp; Displays‎‏‎‎‏‎"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎Suggested Devices‎‏‎‎‏‎"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‏‎‎How broadcasting works‎‏‎‎‏‎"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎Broadcast‎‏‎‎‏‎"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‎People near you with compatible Bluetooth devices can listen to the media you\'re broadcasting‎‏‎‎‏‎"</string>
@@ -1014,5 +1018,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎✱ This screen will turn off‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎Foldable device being unfolded‎‏‎‎‏‎"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‎Foldable device being flipped around‎‏‎‎‏‎"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎Stylus battery low‎‏‎‎‏‎"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%s</xliff:g>‎‏‎‎‏‏‏‎ battery remaining‎‏‎‎‏‎"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎Connect your stylus to a charger‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2dc01f110b2c..3d6419dba9eb 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Límite inferior: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Límite izquierdo: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Límite derecho: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Grabadora de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación constante para una sesión de grabación de pantalla"</string>
@@ -375,7 +379,7 @@
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Pantalla completa"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Una sola app"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Cuando compartas, grabes o transmitas contenido, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo aquel que sea visible en la pantalla o que reproduzcas en el dispositivo. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes y otra información sensible."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Cuando compartas, grabes o transmitas una app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo el contenido que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes y otra información sensible."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Cuando compartas, grabes o transmitas una app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo el contenido que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con las contraseñas, los detalles de pagos, los mensajes y otra información sensible."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartir o grabar una app"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"¿Quieres permitir que esta app comparta o grabe tu pantalla?"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducir <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Acércate para reproducir en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproducir aquí"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se produjo un error. Vuelve a intentarlo."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumen"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Bocinas y pantallas"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la transmisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que transmites"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta pantalla se apagará"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable siendo desplegado"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable siendo girado"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"La pluma stylus tiene poca batería"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c2443daccceb..9839e509acbf 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite inferior"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite izquierdo"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite derecho"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Grabación de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para que se reproduzca en ese dispositivo"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para jugar aquí"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproducir contenido ahí"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Se ha producido un error. Inténtalo de nuevo."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumen"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altavoces y pantallas"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la emisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emisión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que emites"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta pantalla se apagará"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable desplegándose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable mostrado desde varios ángulos"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Batería del lápiz óptico baja"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index b31030a42fe3..5a83eb6fb60a 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alapiir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vasak piir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Parem piir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Võta tagasi"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Teisaldage lähemale, et seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g> esitada"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siin esitamiseks liigutage seadmele <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemale"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Liikuge lähemale, et seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g> esitada"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Midagi läks valesti. Proovige uuesti."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Laadimine"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Helitugevus"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Kõlarid ja ekraanid"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kuidas ülekandmine toimib?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Ülekanne"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Teie läheduses olevad inimesed, kellel on ühilduvad Bluetooth-seadmed, saavad kuulata teie ülekantavat meediat"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ See ekraan lülitatakse välja"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Volditava seadme lahtivoltimine"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Volditava seadme ümberpööramine"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Elektronpliiatsi akutase on madal"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index de9c75f45af8..38db7066608c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Beheko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Ezkerreko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Eskuineko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Pantaila-grabagailua"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
@@ -690,7 +694,7 @@
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantaila blokeatua"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Beroegi egoteagatik itzali da"</string>
<string name="thermal_shutdown_message" msgid="6142269839066172984">"Ohi bezala ari da funtzionatzen telefonoa orain.\nInformazio gehiago lortzeko, sakatu hau."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonoa gehiegi berotu da, eta itzali egin da tenperatura jaisteko. Orain, ohiko moduan dabil.\n\nBerotzearen zergati posibleak:\n • Baliabide asko behar dituzten aplikazioak erabiltzea (adib., jokoak, bideoak edo nabigazio-aplikazioak).\n • Fitxategi handiak deskargatu edo kargatzea.\n • Telefonoa giro beroetan erabiltzea."</string>
+ <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonoa gehiegi berotu da, eta itzali egin da tenperatura jaisteko. Orain, ohiko moduan dabil.\n\nBerotzearen zergati posibleak:\n • Baliabide asko behar dituzten aplikazioak erabiltzea (adib., bideojokoak, bideoak edo nabigazio-aplikazioak).\n • Fitxategi handiak deskargatu edo kargatzea.\n • Telefonoa giro beroetan erabiltzea."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ikusi zaintzeko urratsak"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Berotzen ari da telefonoa"</string>
<string name="high_temp_notif_message" msgid="1277346543068257549">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte.\nInformazio gehiago lortzeko, sakatu hau."</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Erreproduzitu <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> bidez"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desegin"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Gertura ezazu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzeko"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Gerturatu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailura bertan erreproduzitzen ari dena hemen erreproduzitzeko"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzen"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Arazoren bat izan da. Saiatu berriro."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Kargatzen"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Bolumena"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%% <xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Bozgorailuak eta pantailak"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Nola funtzionatzen dute iragarpenek?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Iragarri"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth bidezko gailu bateragarriak dituzten inguruko pertsonek iragartzen ari zaren multimedia-edukia entzun dezakete"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Pantaila itzali egingo da"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Gailu tolesgarria zabaltzen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Gailu tolesgarria biratzen"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Arkatzak bateria gutxi du"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 87aed942d05e..9800da9b78aa 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"مرز پایین <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"مرز سمت چپ <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"مرز سمت راست <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ضبط‌کننده صفحه‌نمایش"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحه‌نمایش"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحه‌نمایش"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> را ازطریق <xliff:g id="APP_LABEL">%2$s</xliff:g> پخش کنید"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"واگرد"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"برای پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g> به دستگاه نزدیک‌تر شوید"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"برای پخش در اینجا، به <xliff:g id="DEVICENAME">%1$s</xliff:g> نزدیک‌تر شوید"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"مشکلی پیش آمد. دوباره امتحان کنید."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"درحال بار کردن"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"میزان صدا"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"بلندگوها و نمایشگرها"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"همه‌فرتستی چطور کار می‌کند"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"همه‌فرستی"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‏افرادی که در اطرافتان دستگاه‌های Bluetooth سازگار دارند می‌توانند به رسانه‌ای که همه‌فرستی می‌کنید گوش کنند"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ این صفحه‌نمایش خاموش خواهد شد"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"دستگاه تاشو درحال باز شدن"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"دستگاه تاشو درحال چرخش به اطراف"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"باتری قلم ضعیف است"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f7bb7f701687..efdc9cb89e17 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alareuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vasen reuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Oikea reuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Näytön tallentaja"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Soita <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="APP_LABEL">%2$s</xliff:g>)"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Kumoa"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Siirry lähemmäs, jotta <xliff:g id="DEVICENAME">%1$s</xliff:g> voi toistaa tämän"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siirrä <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemmäs toistaaksesi täällä"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Toistetaan: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Jotain meni pieleen. Yritä uudelleen."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Latautuminen"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Äänenvoimakkuus"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Kaiuttimet ja näytöt"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Miten lähetys toimii"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Lähetys"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lähistöllä olevat ihmiset, joilla on yhteensopiva Bluetooth-laite, voivat kuunnella lähettämääsi mediaa"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Tämä näyttö sammutetaan"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Taitettava laite taitetaan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Taitettava laite käännetään ympäri"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Näyttökynän akku vähissä"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index be81a9275544..5423c579bf2b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inférieure : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite gauche : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite droite : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Lecture de <xliff:g id="SONG_NAME">%1$s</xliff:g> à partir de <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Rapprochez-vous pour faire jouer le contenu sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez-vous de <xliff:g id="DEVICENAME">%1$s</xliff:g> pour lire le contenu"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Chargement en cours…"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Haut-parleurs et écrans"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement de la diffusion"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Diffusion"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les personnes à proximité disposant d\'appareils Bluetooth compatibles peuvent écouter le contenu multimédia que vous diffusez"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* Cet écran va s\'éteindre"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable en cours de dépliage"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable en train d\'être retourné"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Pile du stylet faible"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 869166321079..c356d7393c12 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inférieure : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite gauche : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite droite : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> depuis <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Rapprochez-vous pour lire sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez l\'appareil pour transférer la diffusion à votre <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Rapprochez-vous de votre <xliff:g id="DEVICENAME">%1$s</xliff:g> pour y lire le contenu"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>…"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Chargement…"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Enceintes et écrans"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement des annonces"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annonce"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les personnes à proximité équipées d\'appareils Bluetooth compatibles peuvent écouter le contenu multimédia que vous diffusez"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Cet écran sera désactivé"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable qui est déplié"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable qui est retourné"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"La batterie du stylet est faible"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index f9738e3b413a..4bc51230c08b 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bordo inferior: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Bordo esquerdo: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Bordo dereito: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Gravadora da pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación en curso sobre unha sesión de gravación de pantalla"</string>
@@ -383,7 +387,7 @@
<string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Cando compartes, gravas ou emites aplicacións, esta aplicación ten acceso a todo o que se vexa ou se reproduza nelas. Polo tanto, debes ter coidado cos contrasinais, os detalles de pago, as mensaxes ou outra información confidencial."</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"O teu administrador de TI bloqueou esta aplicación"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"A política do dispositivo desactivou a opción de capturar a pantalla"</string>
- <string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todas"</string>
+ <string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Xestionar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Notificacións novas"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfacer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Achega o dispositivo para reproducir o contido en: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Achégate ao dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>) para reproducir o contido neste"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducindo contido noutro dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Produciuse un erro. Téntao de novo."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altofalantes e pantallas"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funcionan as difusións?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Difusión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As persoas que estean preto de ti e que dispoñan de dispositivos Bluetooth compatibles poden escoitar o contido multimedia que difundas"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Desactivarase esta pantalla"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pregable abríndose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pregable xirando"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"O lapis óptico ten pouca batería"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index dac1403f8dd5..3075f16860d2 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"નીચેની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ડાબી બાજુની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"જમણી બાજુની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકોર્ડર"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> પર <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચલાવો"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"છેલ્લો ફેરફાર રદ કરો"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવા માટે વધુ નજીક ખસેડો"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"આમાં ચલાવવા માટે ડિવાઇસને <xliff:g id="DEVICENAME">%1$s</xliff:g>ની નજીક ખસેડો"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"કંઈક ખોટું થયું. ફરી પ્રયાસ કરો."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"લોડ થઈ રહ્યું છે"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"વૉલ્યૂમ"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"સ્પીકર અને ડિસ્પ્લે"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"બ્રોડકાસ્ટ પ્રક્રિયાની કામ કરવાની રીત"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"બ્રોડકાસ્ટ કરો"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"સુસંગત બ્લૂટૂથ ડિવાઇસ ધરાવતા નજીકના લોકો તમે જે મીડિયા બ્રોડકાસ્ટ કરી રહ્યાં છો તે સાંભળી શકે છે"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ આ સ્ક્રીન બંધ થઈ જશે"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ અનફોલ્ડ કરવામાં આવી રહ્યું છે"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ ફ્લિપ કરવામાં આવી રહ્યું છે"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"સ્ટાઇલસની બૅટરીમાં ચાર્જ ઓછો છે"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 38d2bffa239a..6828e8d4893d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"निचले किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"बाएं किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"दाएं किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
@@ -371,11 +375,11 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"इस फ़ंक्शन को उपलब्ध कराने वाली सेवा, रिकॉर्ड या कास्ट करते समय, आपकी स्क्रीन पर दिखने वाली या चलाई जाने वाली जानकारी को ऐक्सेस कर सकती है. इसमें पासवर्ड, पैसे चुकाने से जुड़ी जानकारी, फ़ोटो, मैसेज, और चलाए जाने वाले ऑडियो शामिल हैं."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रिकॉर्डिंग या कास्ट करना शुरू करें?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> का इस्तेमाल करके रिकॉर्ड और कास्ट करना शुरू करें?"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> को शेयर या रिकॉर्ड करने की अनुमति दें?"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"क्या आपको शेयर या रिकॉर्ड करने की <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> को अनुमति देनी है?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"पूरी स्क्रीन"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"सिर्फ़ एक ऐप्लिकेशन"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"शेयर, रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> के पास स्क्रीन पर दिख रही हर चीज़ या डिवाइस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, शेयर, रिकॉर्ड या कास्ट करते समय, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज या किसी और संवेदनशील जानकारी को लेकर खास सावधानी बरतें."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"शेयर, रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> के पास उस ऐप्लिकेशन पर दिख रही हर चीज़ या उस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, शेयर, रिकॉर्ड या कास्ट करते समय, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज या किसी और संवेदनशील जानकारी को लेकर खास सावधानी बरतें."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"शेयर, रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> के पास उस ऐप्लिकेशन पर दिख रही हर चीज़ या उस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज या किसी और संवेदनशील जानकारी को लेकर खास सावधानी बरतें."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"जारी रखें"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ऐप्लिकेशन शेयर करें या उसकी रिकॉर्डिंग करें"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"क्या इस ऐप्लिकेशन को शेयर या रिकॉर्ड करने की अनुमति देनी है?"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> पर, <xliff:g id="SONG_NAME">%1$s</xliff:g> चलाएं"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"पहले जैसा करें"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चलाने के लिए, अपने डिवाइस को उसके पास ले जाएं"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"अपने डिवाइस पर मीडिया फ़ाइल ट्रांसफ़र करने के लिए, उसे <xliff:g id="DEVICENAME">%1$s</xliff:g> के पास ले जाएं"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चल रहा है"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"कोई गड़बड़ी हुई. फिर से कोशिश करें."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"लोड हो रहा है"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"वॉल्यूम"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पीकर और डिसप्ले"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्ट करने की सुविधा कैसे काम करती है"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करें"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"आपके आस-पास मौजूद लोग, ब्रॉडकास्ट किए जा रहे मीडिया को सुन सकते हैं. हालांकि, इसके लिए उनके पास ऐसे ब्लूटूथ डिवाइस होने चाहिए जिन पर मीडिया चलाया जा सके"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ यह स्क्रीन बंद हो जाएगी"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फ़ोल्ड किया जा सकने वाला डिवाइस अनफ़ोल्ड किया जा रहा है"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फ़ोल्ड किया जा सकने वाला डिवाइस पलटा जा रहा है"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलस की बैटरी कम है"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7613317734d1..484e3a4577c2 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Donji rub <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Lijevi rub <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Desni rub <xliff:g id="PERCENT">%1$d</xliff:g> posto"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Snimke zaslona s poslovnog profila spremaju se u aplikaciju <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Datoteke"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrada snimanja zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Tekuća obavijest za sesiju snimanja zaslona"</string>
@@ -377,7 +379,7 @@
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Kad dijelite, snimate ili emitirate, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što je vidljivo na vašem zaslonu ili se reproducira na vašem uređaju. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
<string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kad dijelite, snimate ili emitirate aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Nastavi"</string>
- <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Dijeljenje ili snimanje pomoću aplikacije"</string>
+ <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Dijeljenje ili snimanje aplikacije"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Želite li ovoj aplikaciji omogućiti dijeljenje ili bilježenje?"</string>
<string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Kad dijelite, snimate ili emitirate, ova aplikacija ima pristup svemu što je vidljivo na vašem zaslonu ili se reproducira na vašem uređaju. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
<string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Kad dijelite, snimate ili emitirate aplikaciju, ova aplikacija ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> putem aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Približite se radi reprodukcije na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu reproducirali"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije u redu. Pokušajte ponovo."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Učitavanje"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Glasnoća"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i zasloni"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako emitiranje funkcionira"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitiranje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u blizini s kompatibilnim Bluetooth uređajima mogu slušati medije koje emitirate"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ovaj će se zaslon isključiti"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rasklopljen sklopivi uređaj"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Okretanje sklopivog uređaja sa svih strana"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Slaba baterija pisaljke"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c2b94c0b1102..cfa0577c29be 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alsó rész <xliff:g id="PERCENT">%1$d</xliff:g> százaléka"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Bal oldali rész <xliff:g id="PERCENT">%1$d</xliff:g> százaléka"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Jobb oldali rész <xliff:g id="PERCENT">%1$d</xliff:g> százaléka"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Képernyőrögzítő"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Folyamatban lévő értesítés képernyőrögzítési munkamenethez"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című számának lejátszása innen: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> lejátszása innen: <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Visszavonás"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Menjen közelebb a következőn való lejátszáshoz: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Menjen közelebb a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközhöz, hogy itt játszhassa le a tartalmat"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Menjen közelebb, ha itt szeretné lejátszani: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hiba történt. Próbálkozzon újra."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Betöltés…"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hangerő"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hangfalak és kijelzők"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"A közvetítés működése"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Közvetítés"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"A közelben tartózkodó, kompatibilis Bluetooth-eszközzel rendelkező személyek meghallgathatják az Ön közvetített médiatartalmait"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ A képernyő kikapcsol"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Összehajtható eszköz kihajtása"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Összehajtható eszköz körbeforgatása"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Az érintőceruza töltöttsége alacsony"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 5623ecfb7f29..8f7ecf600138 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ներքևի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Ձախ կողմի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Աջ կողմի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Էկրանի տեսագրիչ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Նվագարկել <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="APP_LABEL">%2$s</xliff:g> հավելվածից"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Հետարկել"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ավելի մոտ եկեք՝ <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքում նվագարկելու համար"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ավելի մոտեցեք «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքին՝ նվագարկումը սկսելու համար"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Նվագարկվում է «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքում"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Բեռնվում է"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ձայնի ուժգնություն"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Բարձրախոսներ և էկրաններ"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ինչպես է աշխատում հեռարձակումը"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Հեռարձակում"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ձեր մոտակայքում գտնվող՝ համատեղելի Bluetooth սարքերով մարդիկ կարող են լսել մեդիա ֆայլերը, որոնք դուք հեռարձակում եք։"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Այս էկրանը կանջատվի"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ծալովի սարք՝ բացված վիճակում"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Ծալովի սարք՝ շրջված վիճակում"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Ստիլուսի մարտկոցի լիցքի ցածր մակարդակ"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index bf5f8b01848c..a427a2c56f55 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Batas bawah <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Batas kiri <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Batas kanan <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Perekam Layar"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifikasi yang sedang berjalan untuk sesi rekaman layar"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Putar <xliff:g id="SONG_NAME">%1$s</xliff:g> dari <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Urungkan"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Dekatkan untuk memutar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan ke <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk memutar di sini"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Terjadi error. Coba lagi."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Memuat"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speaker &amp; Layar"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara kerja siaran"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siaran"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang di dekat Anda dengan perangkat Bluetooth yang kompatibel dapat mendengarkan media yang sedang Anda siarkan"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Layar ini akan dinonaktifkan"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Perangkat foldable sedang dibentangkan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Perangkat foldable sedang dibalik"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Baterai stilus lemah"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index f3efb8624333..c12fb4822cf9 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Neðri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vinstri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Hægri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skjáupptaka"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spila <xliff:g id="SONG_NAME">%1$s</xliff:g> í <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Afturkalla"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Færðu nær til að spila í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Færðu tækið nær <xliff:g id="DEVICENAME">%1$s</xliff:g> til að spila hér"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Í spilun í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Eitthvað fór úrskeiðis. Reyndu aftur."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Hleður"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hljóðstyrkur"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hátalarar og skjáir"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Svona virkar útsending"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Útsending"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Fólk nálægt þér með samhæf Bluetooth-tæki getur hlustað á efnið sem þú sendir út"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Slökkt verður á þessum skjá"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Samanbrjótanlegt tæki opnað"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Samanbrjótanlegu tæki snúið við"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Rafhlaða pennans er að tæmast"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e8c6a5b21308..5c52bc13974e 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inferiore, <xliff:g id="PERCENT">%1$d</xliff:g> percento"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite sinistro, <xliff:g id="PERCENT">%1$d</xliff:g> percento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite destro, <xliff:g id="PERCENT">%1$d</xliff:g> percento"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Registrazione dello schermo"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaboraz. registraz. schermo"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string>
@@ -371,7 +375,7 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"Il servizio che offre questa funzione avrà accesso a tutte le informazioni visibili sul tuo schermo o riprodotte dal tuo dispositivo durante la registrazione o la trasmissione. Sono incluse informazioni quali password, dettagli sui pagamenti, foto, messaggi e audio riprodotto."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vuoi avviare la registrazione o la trasmissione?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Vuoi avviare la registrazione o la trasmissione con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Consenti a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> di condividere o registrare?"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Consentire a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> di condividere o registrare?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Schermo intero"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Una sola app"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Quando condividi, registri o trasmetti, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ha accesso a qualsiasi elemento visibile sul tuo schermo o in riproduzione sul tuo dispositivo. Presta quindi attenzione a password, dati di pagamento, messaggi o altre informazioni sensibili."</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Riproduci <xliff:g id="SONG_NAME">%1$s</xliff:g> da <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Annulla"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Avvicinati per riprodurre su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Avvicinati a <xliff:g id="DEVICENAME">%1$s</xliff:g> per riprodurre i contenuti qui"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Si è verificato un errore. Riprova."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Caricamento in corso…"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speaker e display"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Come funziona la trasmissione"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annuncio"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Le persone vicine a te che hanno dispositivi Bluetooth compatibili possono ascoltare i contenuti multimediali che stai trasmettendo"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Questo schermo verrà disattivato"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pieghevole che viene aperto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pieghevole che viene capovolto"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Batteria stilo in esaurimento"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 690b6b22710c..de95f2e372ae 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> אחוז מהשוליים התחתונים"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> אחוז מהשוליים השמאליים"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> אחוז מהשוליים הימניים"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"צילומי מסך בפרופיל העבודה נשמרים באפליקציה <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"קבצים"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
@@ -98,8 +100,8 @@
<string name="screenrecord_description" msgid="1123231719680353736">"‏בזמן ההקלטה, מערכת Android יכולה לתעד מידע רגיש שגלוי במסך או מופעל במכשיר שלך. מידע זה כולל סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו."</string>
<string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"הקלטה של כל המסך"</string>
<string name="screenrecord_option_single_app" msgid="5954863081500035825">"הקלטה של אפליקציה אחת"</string>
- <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"‏בזמן ההקלטה, תהיה ל-Android גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
- <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"‏בזמן הקלטה של אפליקציה, תהיה ל-Android גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+ <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"‏בזמן ההקלטה, תהיה ל-Android גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. חשוב להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+ <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"‏בזמן הקלטה של אפליקציה, תהיה ל-Android גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. חשוב להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
<string name="screenrecord_start_recording" msgid="348286842544768740">"התחלת ההקלטה"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"הקלטת אודיו"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"אודיו מהמכשיר"</string>
@@ -374,8 +376,8 @@
<string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"לאפשר לאפליקציה <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> לשתף או להקליט?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"כל המסך"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"אפליקציה אחת"</string>
- <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"‏בזמן שיתוף, הקלטה או העברה (cast) תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"‏בזמן שיתוף, הקלטה או העברה (cast) של אפליקציה, תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+ <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"‏בזמן שיתוף, הקלטה או העברה (cast) תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. חשוב להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"‏בזמן שיתוף, הקלטה או העברה (cast) של אפליקציה, תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. חשוב להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"המשך"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"שיתוף או הקלטה של אפליקציה"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"לאפשר לאפליקציה הזו לשתף או להקליט?"</string>
@@ -849,12 +851,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> מ-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ביטול"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"צריך להתקרב כדי להפעיל מוזיקה במכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"צריך להתקרב אל <xliff:g id="DEVICENAME">%1$s</xliff:g> כדי להפעיל כאן"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"צריך להתקרב כדי להפעיל מדיה במכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"פועלת ב-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"משהו השתבש. יש לנסות שוב."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"בטעינה"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"טאבלט"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"עוצמת הקול"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"‎<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%‎‎"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"רמקולים ומסכים"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"הצעות למכשירים"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"הסבר על שידורים"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"שידור"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‏אנשים בקרבת מקום עם מכשירי Bluetooth תואמים יכולים להאזין למדיה שמשודרת על ידך"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ המסך יכבה"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"מכשיר מתקפל עובר למצב לא מקופל"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"מכשיר מתקפל עובר למצב מהופך"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"הסוללה של הסטיילוס חלשה"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 5bd580ccc603..3d4551c4b747 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"下部の境界線 <xliff:g id="PERCENT">%1$d</xliff:g> パーセント"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左の境界線 <xliff:g id="PERCENT">%1$d</xliff:g> パーセント"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右の境界線 <xliff:g id="PERCENT">%1$d</xliff:g> パーセント"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"スクリーン レコーダー"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"画面の録画を処理しています"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"画面の録画セッション中の通知"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> を <xliff:g id="APP_LABEL">%2$s</xliff:g> で再生"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"元に戻す"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生するにはもっと近づけてください"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ここで再生するには<xliff:g id="DEVICENAME">%1$s</xliff:g>に近づいてください"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"エラーが発生しました。もう一度お試しください。"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"読み込んでいます"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"スピーカーとディスプレイ"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ブロードキャストの仕組み"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ブロードキャスト"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth 対応デバイスを持っている付近のユーザーは、あなたがブロードキャストしているメディアを聴けます"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱この画面は OFF になります"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"折りたたみ式デバイスが広げられている"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"折りたたみ式デバイスがひっくり返されている"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"タッチペンのバッテリー残量が少なくなっています"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index d25daf440ce2..61280d3d425f 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ქვედა ზღვარი: <xliff:g id="PERCENT">%1$d</xliff:g> პროცენტი"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"მარცხენა ზღვარი: <xliff:g id="PERCENT">%1$d</xliff:g> პროცენტი"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"მარჯვენა ზღვარი: <xliff:g id="PERCENT">%1$d</xliff:g> პროცენტი"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"სამუშაო ეკრანის ანაბეჭდები ინახება <xliff:g id="APP">%1$s</xliff:g> აპში"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ფაილები"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ეკრანის ჩამწერი"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ეკრანის ჩანაწერი მუშავდება"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"უწყვეტი შეტყობინება ეკრანის ჩაწერის სესიისთვის"</string>
@@ -98,7 +100,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"ჩაწერის განმავლობაში Android სისტემას შეუძლია აღბეჭდოს ნებისმიერი სენსიტიური ინფორმაცია, რომელიც თქვენს ეკრანზე გამოჩნდება ან თქვენს მოწყობილობაზე დაიკვრება. აღნიშნული მოიცავს პაროლებს, გადახდის დეტალებს, ფოტოებს, შეტყობინებებსა და აუდიოს."</string>
<string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"მთელი ეკრანის ჩაწერა"</string>
<string name="screenrecord_option_single_app" msgid="5954863081500035825">"ერთი აპის ჩაწერა"</string>
- <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"სანამ აპის ჩაწერას ახორციელებთ, Android-ს აქვს წვდომა ყველაფერზე, რაც ჩანს თქვენს ეკრანზე ან უკრავს თქვენი მოწყობილობის მეშვეობით. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან."</string>
+ <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"ჩაწერის განხორციელებისას Android-ს აქვს წვდომა ყველაფერზე, რაც თქვენს ეკრანზე ჩანს ან უკრავს თქვენი მოწყობილობის მეშვეობით. შესაბამისად, გამოიჩინეთ სიფრთხილე პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან თუ სხვა მგრძნობიარე ინფორმაციასთან დაკავშირებით."</string>
<string name="screenrecord_warning_single_app" msgid="7760723997065948283">"სანამ აპის ჩაწერას ახორციელებთ, Android-ს აქვს წვდომა ყველაფერზე, რაც ჩანს აპში ან ითამაშეთ. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან"</string>
<string name="screenrecord_start_recording" msgid="348286842544768740">"ჩაწერის დაწყება"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"აუდიოს ჩაწერა"</string>
@@ -371,11 +373,11 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"ამ ფუნქციის მომწოდებელ სერვისს ექნება წვდომა ყველა ინფორმაციაზე, რომელიც თქვენს ეკრანზე გამოჩნდება ან თქვენს მოწყობილობაზე დაიკვრება ჩაწერის ან ტრანსლირების განმავლობაში. აღნიშნული მოიცავს ისეთ ინფორმაციას, როგორიც არის პაროლები, გადახდის დეტალები, ფოტოები, შეტყობინებები და თქვენ მიერ დაკრული აუდიო."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"დაიწყოს ჩაწერა ან ტრანსლირება?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"დაიწყოს ჩაწერა ან ტრანსლირება <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ით?"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"გსურთ დართოთ ნება <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> გაზიარების ან ჩაწერისთვის?"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"გსურთ, დართოთ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ს გაზიარების ან ჩაწერის ნება?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"მთელი ეკრანი"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"ერთი აპი"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"როდესაც თქვენ აზიარებთ, ჩაწერთ ან ტრანსლირებთ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> აქვს წვდომა ყველაფერზე, რაც ჩანს თქვენს ეკრანზე ან უკრავს თქვენს მოწყობილობაზე. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"აპის გაზიარებისას, ჩაწერისას ან ტრანსლირებისას <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> აქვს წვდომა აქვს ყველაფერზე, რაც ჩანს აპში ან ითამაშეთ. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"აპის გაზიარებისას, ჩაწერისას ან ტრანსლირებისას <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ს აქვს წვდომა ყველაფერზე, რაც ამ აპში ჩანს და მასშია გაშვებული. შესაბამისად, გამოიჩინეთ სიფრთხილე პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან თუ სხვა მგრძნობიარე ინფორმაციასთან დაკავშირებით."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"გაგრძელება"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"გააზიარეთ ან ჩაწერეთ აპი"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"გსურთ ამ აპისთვის გაზიარების ან ჩაწერის უფლების მიცემა?"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g>-დან"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"მოქმედების გაუქმება"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"მიიტანეთ უფრო ახლოს, რომ დაუკრათ <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"მიუახლოვდით <xliff:g id="DEVICENAME">%1$s</xliff:g>-ს მისი მეშვეობით დასაკრავად"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"იტვირთება"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ტაბლეტი"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ხმა"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"დინამიკები და დისპლეები"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"შემოთავაზებული მოწყობილობები"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ტრანსლირების მუშაობის პრინციპი"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ტრანსლაცია"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"თქვენთან ახლოს მყოფ ხალხს თავსებადი Bluetooth მოწყობილობით შეუძლიათ თქვენ მიერ ტრანსლირებული მედიის მოსმენა"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ეს ეკრანი გამოირთვება"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"დასაკეცი მოწყობილობა იხსნება"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"დასაკეცი მოწყობილობა ტრიალებს"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"სტილუსის ბატარეა დაცლის პირასაა"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index bb24d6af3c0a..1e96422b7946 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Төменгі шектік сызық: <xliff:g id="PERCENT">%1$d</xliff:g> пайыз"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Сол жақ шектік сызық: <xliff:g id="PERCENT">%1$d</xliff:g> пайыз"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Оң жақ шектік сызық: <xliff:g id="PERCENT">%1$d</xliff:g> пайыз"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Экран жазғыш"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> қолданбасында \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әнін ойнату"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Қайтару"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында музыка ойнату үшін оған жақындаңыз."</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Осы жерде ойнау үшін <xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысына жақындаңыз"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бірдеңе дұрыс болмады. Қайталап көріңіз."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Жүктеліп жатыр"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Дыбыс деңгейі"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Динамиктер мен дисплейлер"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Тарату қалай жүзеге асады"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Тарату"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Үйлесімді Bluetooth құрылғылары бар маңайдағы адамдар сіз таратып жатқан медиамазмұнды тыңдай алады."</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Бұл экран өшіріледі."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Бүктемелі құрылғы ашылып жатыр."</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Бүктемелі құрылғы аударылып жатыр."</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Стилус батареясының заряды аз"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 65953058322d..25598777ed21 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"បន្ទាត់បែងចែក​ខាងក្រោម <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"បន្ទាត់បែងចែក​ខាងឆ្វេង <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"បន្ទាត់បែងចែក​ខាងស្ដាំ <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថត​វីដេអូអេក្រង់"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុង​ដំណើរការ​ការថតអេក្រង់"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹង​ដែល​កំពុង​ដំណើរការ​សម្រាប់​រយៈពេលប្រើ​ការថត​សកម្មភាព​អេក្រង់"</string>
@@ -371,7 +375,7 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"សេវាកម្មដែល​ផ្ដល់​មុខងារ​នេះ​នឹងមាន​សិទ្ធិ​ចូលប្រើ​ព័ត៌មាន​ទាំងអស់​ដែល​អាច​មើលឃើញ​នៅលើ​អេក្រង់​របស់អ្នក ឬ​ដែលចាក់​ពីឧបករណ៍​របស់អ្នក នៅពេល​កំពុង​ថត ឬភ្ជាប់។ ព័ត៌មាន​នេះមាន​ដូចជា ពាក្យសម្ងាត់ ព័ត៌មាន​លម្អិត​អំពីការទូទាត់​ប្រាក់ រូបថត សារ និង​សំឡេង​ដែល​អ្នកចាក់​ជាដើម។"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ចាប់ផ្ដើម​ថត ឬភ្ជាប់​មែនទេ?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"ចាប់ផ្ដើម​ថត ឬភ្ជាប់​ដោយប្រើ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ឬ?"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"អនុញ្ញាតឱ្យ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ចែករំលែក ឬថតទេ?"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"អនុញ្ញាតឱ្យ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ចែករំលែក ឬថត?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"អេក្រង់ទាំងមូល"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"កម្មវិធីតែមួយ"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬបញ្ជូន <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មានសិទ្ធិចូលប្រើប្រាស់អ្វីៗដែលបង្ហាញឱ្យឃើញនៅលើអេក្រង់របស់អ្នក ឬលេងនៅលើឧបករណ៍របស់អ្នក។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះពាក្យសម្ងាត់ ព័ត៌មាន​លម្អិតអំពី​ការ​ទូទាត់ប្រាក់ សារ ឬព័ត៌មានរសើបផ្សេងទៀត។"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ចាក់ <xliff:g id="SONG_NAME">%1$s</xliff:g> ពី <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ត្រឡប់វិញ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"រំកិលឱ្យកាន់តែជិត ដើម្បីចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"រំកិលឱ្យកាន់តែជិត <xliff:g id="DEVICENAME">%1$s</xliff:g> ដើម្បីចាក់នៅទីនេះ"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"កំពុង​ចាក់​​នៅ​លើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"កំពុងផ្ទុក"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើល​កម្មវិធី"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"រកមិន​ឃើញទេ"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"កម្រិតសំឡេង"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ឧបករណ៍បំពងសំឡេង និងផ្ទាំងអេក្រង់"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"របៀបដែលការផ្សាយដំណើរការ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ការ​ផ្សាយ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"មនុស្សនៅជិត​អ្នកដែលមាន​ឧបករណ៍ប៊្លូធូស​ត្រូវគ្នា​អាចស្តាប់​មេឌៀ​ដែលអ្នកកំពុងផ្សាយបាន"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ អេក្រង់នេះនឹងបិទ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"ថ្មប៊ិកនៅសល់តិច"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 81a37f31aa8f..12d96c342647 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ಕೆಳಗಿನ ಬೌಂಡರಿ ಶೇಕಡಾ <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ಎಡಭಾಗದ ಬೌಂಡರಿ ಶೇಕಡಾ <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ಬಲಭಾಗದ ಬೌಂಡರಿ ಶೇಕಡಾ <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡರ್"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೆಶನ್‌ಗಾಗಿ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಅಧಿಸೂಚನೆ"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%2$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ರದ್ದುಗೊಳಿಸಿ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಅದರ ಹತ್ತಿರಕ್ಕೆ ಸರಿಯಿರಿ"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು <xliff:g id="DEVICENAME">%1$s</xliff:g> ಸಮೀಪಕ್ಕೆ ಹೋಗಿ"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ವಾಲ್ಯೂಮ್"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ಸ್ಪೀಕರ್‌ಗಳು ಮತ್ತು ಡಿಸ್‌ಪ್ಲೇಗಳು"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ಪ್ರಸಾರವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ಪ್ರಸಾರ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ಹೊಂದಾಣಿಕೆಯಾಗುವ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ಹೊಂದಿರುವ ಸಮೀಪದಲ್ಲಿರುವ ಜನರು ನೀವು ಪ್ರಸಾರ ಮಾಡುತ್ತಿರುವ ಮಾಧ್ಯಮವನ್ನು ಆಲಿಸಬಹುದು"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ಈ ಸ್ಕ್ರೀನ್ ಆಫ್ ಆಗುತ್ತದೆ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಸುತ್ತಲೂ ತಿರುಗಿಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"ಸ್ಟೈಲಸ್ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಿದೆ"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 1570a6aa2370..e42e10ef753a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"하단 가장자리 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"왼쪽 가장자리 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"오른쪽 가장자리 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"화면 녹화"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
@@ -371,11 +375,11 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"이 기능을 제공하는 서비스는 녹화 또는 전송 중에 화면에 표시되거나 기기에서 재생되는 모든 정보에 액세스할 수 있습니다. 여기에는 비밀번호, 결제 세부정보, 사진, 메시지, 재생하는 오디오 같은 정보가 포함됩니다."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"녹화 또는 전송을 시작하시겠습니까?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>으로 녹화 또는 전송을 시작하시겠습니까?"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 공유 또는 녹화를 허용할까요?"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 공유 또는 녹화하도록 허용할까요?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"전체 화면"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"단일 앱"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"공유하거나 녹화하거나 전송할 때 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 앱에서 화면에 표시되거나 기기에서 재생되는 모든 항목에 액세스할 수 있습니다. 따라서 비밀번호, 결제 세부정보, 메시지 등 민감한 정보가 노출되지 않도록 주의하세요."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"앱을 공유하거나 녹화하거나 전송할 때는 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 해당 앱에 표시되거나 재생되는 모든 항목에 액세스할 수 있으므로 비밀번호, 결제 세부정보, 메시지 등 민감한 정보가 노출되지 않도록 주의하세요."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"앱을 공유하거나 녹화하거나 전송할 때는 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 해당 앱에 표시되거나 앱에서 재생되는 모든 항목에 액세스할 수 있으므로 비밀번호, 결제 세부정보, 메시지 등 민감한 정보가 노출되지 않도록 주의하세요."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"계속"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"앱 공유 또는 녹화"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"앱에서 공유하거나 기록하도록 허용하시겠습니까?"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>에서 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"실행취소"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생하려면 기기를 더 가까이로 옮기세요."</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"현재 기기에서 재생하려면 <xliff:g id="DEVICENAME">%1$s</xliff:g>에 더 가까이 이동합니다."</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"문제가 발생했습니다. 다시 시도해 주세요."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"로드 중"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"볼륨"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"스피커 및 디스플레이"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"브로드캐스팅 작동 원리"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"브로드캐스트"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"호환되는 블루투스 기기를 가진 근처의 사용자가 내가 브로드캐스트 중인 미디어를 수신 대기할 수 있습니다."</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 이 화면이 꺼집니다."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"폴더블 기기를 펼치는 모습"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"폴더블 기기를 뒤집는 모습"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"스타일러스 배터리 부족"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index b1206840b722..ec9e96200816 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ылдый жагы <xliff:g id="PERCENT">%1$d</xliff:g> пайызга"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Сол жагы <xliff:g id="PERCENT">%1$d</xliff:g> пайызга"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Оң жагы <xliff:g id="PERCENT">%1$d</xliff:g> пайызга"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
@@ -371,16 +375,16 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"Жаздырып же тышкы экранга чыгарып жатканда, бул колдонмо экраныңыздагы бардык маалыматты же түзмөктө ойнолуп жаткан бардык нерселерди (сырсөздөрдү, төлөмдүн чоо-жайын, сүрөттөрдү, билдирүүлөрдү жана угуп жаткан аудиофайлдарды) көрө алат."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жаздырып же тышкы экранга чыгарып баштайсызбы?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосу аркылуу жаздырып же тышкы экранга чыгарып баштайсызбы?"</string>
- <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна бөлүшүүгө же жаздырууга уруксат бересизби?"</string>
+ <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна экранды бөлүшүүгө же андан видео тартууга уруксат бересизби?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Бүтүндөй экран"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Жалгыз колдонмо"</string>
- <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Бөлүшүп, жаздырып же тышкы экранда бөлүшкөндө <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экраныңызда көрүнүп жана түзмөктө ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөм маалыматын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Бөлүшүп, жаздырып же тышкы экранда бөлүшкөндө <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ал колдонмодо көрүнүп жана ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөм маалыматын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
+ <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Экранды көрсөтүп, тышка чыгарып же андан видео тартып жатканда, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> түзмөктүн экранындагы нерселердин баарын көрө алат. Андыктан сырсөздөр, төлөм маалыматы, билдирүүлөр сыяктуу купуя маалыматты киргизүүдө же көрүүдө этият болуңуз."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Экранды көрсөтүп, тышка чыгарып же андан видео тартып жатканда, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> түзмөктүн экранындагы нерселердин баарын көрө алат. Андыктан сырсөздөр, төлөм маалыматы, билдирүүлөр сыяктуу купуя маалыматты киргизүүдө же көрүүдө этият болуңуз."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Улантуу"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Колдонмону бөлүшүү же жаздыруу"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Бул колдонмого бөлүшүп же жаздырууга уруксат бересизби?"</string>
- <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Бөлүшүп, жаздырып же тышкы экранга чыгарганда бул колдонмо экраныңызда көрүнүп жана түзмөктө ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
- <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Бөлүшүп, жаздырып же тышкы экранга чыгарганда бул колдонмо ал колдонмодо көрсөтүлүп жана ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
+ <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Экранды көрсөтүп, тышка чыгарып же андан видео тартып жатканда, бул колдонмо түзмөктүн экранындагы нерселердин баарын көрө алат. Андыктан сырсөздөр, төлөм маалыматы, билдирүүлөр сыяктуу купуя маалыматты киргизүүдө же көрүүдө этият болуңуз."</string>
+ <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Экранды көрсөтүп, тышка чыгарып же андан видео тартып жатканда, бул колдонмо түзмөктүн экранындагы нерселердин баарын көрө алат. Андыктан сырсөздөр, төлөм маалыматы, билдирүүлөр сыяктуу купуя маалыматты киргизүүдө же көрүүдө этият болуңуз."</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"IT администраторуңуз бөгөттөп койгон"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Түзмөк саясаты экрандагыны тартып алууну өчүрүп койгон"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string>
@@ -745,7 +749,7 @@
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Жеткиликтүү болгондо мобилдик Интернет автоматтык түрдө которулбайт"</string>
<string name="auto_data_switch_dialog_negative_button" msgid="2370876875999891444">"Жок, рахмат"</string>
<string name="auto_data_switch_dialog_positive_button" msgid="8531782041263087564">"Ооба, которулуу"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"Уруксат берүү сурамыңыз көрүнбөй калгандыктан, Жөндөөлөр жообуңузду ырастай албай жатат."</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"Уруксат берүү сурамыңыз көрүнбөй калгандыктан, Параметрлер жообуңузду ырастай албай жатат."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосуна <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөтүүгө уруксат берилсинби?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунун маалыматын окуйт"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунда аракеттерди аткарат"</string>
@@ -836,7 +840,7 @@
<string name="controls_media_active_session" msgid="3146882316024153337">"Учурдагы медиа сеансын жашыруу мүмкүн эмес."</string>
<string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жашыруу"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string>
- <string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string>
+ <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ыры (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотулуп жатат"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ичинен <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
<string name="controls_media_button_play" msgid="2705068099607410633">"Ойнотуу"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотуу"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын <xliff:g id="APP_LABEL">%2$s</xliff:g> колдонмосунан ойнотуу"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Кайтаруу"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүндө ойнотуу үчүн жакыныраак жылдырыңыз"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Бул жерде ойнотуу үчүн <xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүнө жакындатыңыз"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүндө ойнотуу үчүн жакындатыңыз"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Жүктөлүүдө"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Үндүн катуулугу"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Динамиктер жана дисплейлер"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Кабарлоо кантип иштейт"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Кабарлоо"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Шайкеш Bluetooth түзмөктөрү болгон жакын жердеги кишилер кабарлап жаткан медиаңызды уга алышат"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Бул экран өчөт"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ачылып турган бүктөлмө түзмөк"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Оодарылып жаткан бүктөлмө түзмөк"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Стилустун батареясы отурайын деп калды"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 446deb05cf00..0b8a9de5e1cc 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ຂອບເຂດທາງລຸ່ມ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ຂອບເຂດທາງຊ້າຍ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ຂອບເຂດທາງຂວາ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ກຳລັງປະມວນຜົນການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ຫຼິ້ນ <xliff:g id="SONG_NAME">%1$s</xliff:g> ຈາກ <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ຍົກເລີກ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"ຍ້າຍໄປໃກ້ຂຶ້ນເພື່ອຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ກະລຸນາຍ້າຍເຂົ້າໃກ້ <xliff:g id="DEVICENAME">%1$s</xliff:g> ເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ. ກະລຸນາລອງໃໝ່."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ກຳລັງໂຫຼດ"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ລະດັບສຽງ"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ລຳໂພງ ແລະ ຈໍສະແດງຜົນ"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ການອອກອາກາດເຮັດວຽກແນວໃດ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ອອກອາກາດ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ຄົນທີ່ຢູ່ໃກ້ທ່ານທີ່ມີອຸປະກອນ Bluetooth ທີ່ເຂົ້າກັນໄດ້ຈະສາມາດຟັງມີເດຍທີ່ທ່ານກຳລັງອອກອາກາດຢູ່ໄດ້"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ໜ້າຈໍນີ້ຈະປິດ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ອຸປະກອນທີ່ພັບໄດ້ກຳລັງກາງອອກ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ອຸປະກອນທີ່ພັກໄດ້ກຳລັງປີ້ນໄປມາ"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"ແບັດເຕີຣີປາກກາເຫຼືອໜ້ອຍ"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index db518c100a0d..901773259470 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Apatinė riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kairioji riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Dešinioji riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrano vaizdo įrašytuvas"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Leisti „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ iš „<xliff:g id="APP_LABEL">%2$s</xliff:g>“"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Anuliuoti"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Prieikite arčiau, kad galėtumėte leisti įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Perkelkite arčiau „<xliff:g id="DEVICENAME">%1$s</xliff:g>“, kad būtų galima leisti čia"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kažkas ne taip. Bandykite dar kartą."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Įkeliama"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Garsumas"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Garsiakalbiai ir ekranai"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kaip veikia transliacija"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transliacija"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Netoliese esantys žmonės, turintys suderinamus „Bluetooth“ įrenginius, gali klausyti jūsų transliuojamos medijos"</string>
@@ -1015,5 +1023,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Šis ekranas išsijungs"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Lankstomasis įrenginys išlankstomas"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Lankstomasis įrenginys apverčiamas"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Senka rašiklio akumuliatorius"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Liko akumuliatoriaus įkrovos: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Prijunkite rašiklį prie kroviklio"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5ea8da2889d8..c4cdc06a10c3 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Apakšmala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kreisā mala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Labā mala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrāna ierakstītājs"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Atskaņojiet failu “<xliff:g id="SONG_NAME">%1$s</xliff:g>” no lietotnes <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Atsaukt"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Pārvietojiet savu ierīci tuvāk, lai atskaņotu mūziku ierīcē “<xliff:g id="DEVICENAME">%1$s</xliff:g>”."</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pārvietojieties tuvāk ierīcei “<xliff:g id="DEVICENAME">%1$s</xliff:g>”, lai atskaņotu šeit"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Notiek atskaņošana ierīcē <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Radās kļūda. Mēģiniet vēlreiz."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Notiek ielāde"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Skaļums"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Skaļruņi un displeji"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kā darbojas apraide"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Apraide"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Tuvumā esošās personas ar saderīgām Bluetooth ierīcēm var klausīties jūsu apraidīto multivides saturu."</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Šis ekrāns tiks izslēgts."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Salokāma ierīce tiek atlocīta"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Salokāma ierīce tiek apgriezta"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Zems skārienekrāna pildspalvas akumulatora līmenis"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 0575b102e405..cbdee207e050 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Долна граница <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Лева граница <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Десна граница <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Сликите од екранот во работниот профил се зачувуваат во апликацијата <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Датотеки"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач на екран"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Се обработува снимка од екран"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пуштете <xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Врати"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Приближете се за да пуштите на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за да пуштите тука"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пуштено на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Нешто не е во ред. Обидете се повторно."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Се вчитува"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Јачина на звук"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Звучници и екрани"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Предложени уреди"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционира емитувањето"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитување"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Луѓето во ваша близина со компатибилни уреди со Bluetooth може да ги слушаат аудиозаписите што ги емитувате"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Екранов ќе се исклучи"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Преклопувачки уред се отклопува"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Преклопувачки уред се врти"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Слаба батерија на пенкало"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 9a2353c6b8ad..ac5c0747a47b 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"താഴെയുള്ള അതിർത്തി <xliff:g id="PERCENT">%1$d</xliff:g> ശതമാനം"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ഇടത് വശത്തെ അതിർത്തി <xliff:g id="PERCENT">%1$d</xliff:g> ശതമാനം"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"വലത് വശത്തെ അതിർത്തി <xliff:g id="PERCENT">%1$d</xliff:g> ശതമാനം"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"ഔദ്യോഗിക പ്രൊഫൈലിന്റെ സ്ക്രീന്‍ഷോട്ടുകൾ <xliff:g id="APP">%1$s</xliff:g> ആപ്പിൽ സംരക്ഷിച്ചു"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ഫയലുകൾ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"സ്ക്രീൻ റെക്കോർഡർ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%2$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുക"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"പഴയപടിയാക്കുക"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യാൻ അടുത്തേക്ക് നീക്കുക"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ഇവിടെ പ്ലേ ചെയ്യാൻ <xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിന് അടുത്തേക്ക് നീക്കുക"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ലോഡ് ചെയ്യുന്നു"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ടാബ്‌ലെറ്റ്"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്‌ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"വോളിയം"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"സ്‌പീക്കറുകളും ഡിസ്പ്ലേകളും"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"നിർദ്ദേശിച്ച ഉപകരണങ്ങൾ"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ബ്രോഡ്‌കാസ്‌റ്റ് എങ്ങനെയാണ് പ്രവർത്തിക്കുന്നത്"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ബ്രോഡ്‌കാസ്റ്റ്"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"അനുയോജ്യമായ Bluetooth ഉപകരണങ്ങളോടെ സമീപമുള്ള ആളുകൾക്ക് നിങ്ങൾ ബ്രോഡ്‌കാസ്‌റ്റ് ചെയ്യുന്ന മീഡിയ കേൾക്കാനാകും"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ഈ സ്ക്രീൻ ഓഫാകും"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം അൺഫോൾഡ് ആകുന്നു"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം, കറങ്ങുന്ന വിധത്തിൽ ഫ്ലിപ്പ് ആകുന്നു"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"സ്റ്റൈലസിന്റെ ബാറ്ററി ചാർജ് കുറവാണ്"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 08c47b0f4df4..cb77336df77e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Доод талын хязгаар <xliff:g id="PERCENT">%1$d</xliff:g> хувь"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Зүүн талын хязгаар <xliff:g id="PERCENT">%1$d</xliff:g> хувь"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Баруун талын хязгаар <xliff:g id="PERCENT">%1$d</xliff:g> хувь"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Дэлгэцийн үйлдэл бичигч"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g>-г <xliff:g id="APP_LABEL">%2$s</xliff:g> дээр тоглуулах"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Болих"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулахын тулд төхөөрөмжөө ойртуулна уу"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Энд тоглуулахын тулд <xliff:g id="DEVICENAME">%1$s</xliff:g>-д ойртоно уу"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Алдаа гарлаа. Дахин оролдоно уу."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Ачаалж байна"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Дууны түвшин"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Чанга яригч ба дэлгэц"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Нэвтрүүлэлт хэрхэн ажилладаг вэ?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Нэвтрүүлэлт"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Тохиромжтой Bluetooth төхөөрөмжүүдтэй таны ойролцоох хүмүүс таны нэвтрүүлж буй медиаг сонсох боломжтой"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Энэ дэлгэц унтарна"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Эвхэгддэг төхөөрөмжийг дэлгэж байна"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Эвхэгддэг төхөөрөмжийг хөнтөрч байна"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Мэдрэгч үзэгний батарей бага байна"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 103e8d204772..4f0b83fc63ae 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"खालील सीमेपासून <xliff:g id="PERCENT">%1$d</xliff:g> टक्के"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"डाव्या सीमेपासून <xliff:g id="PERCENT">%1$d</xliff:g> टक्के"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"उजव्या सीमेपासून <xliff:g id="PERCENT">%1$d</xliff:g> टक्के"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रेकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> मध्ये <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले करा"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"पहिल्यासारखे करा"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले करण्यासाठी जवळ जा"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"येथे प्ले करण्यासाठी <xliff:g id="DEVICENAME">%1$s</xliff:g> च्या जवळ जा"</string>
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले केला जात आहे"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले होत आहे"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"लोड करत आहे"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"व्हॉल्यूम"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पीकर आणि डिस्प्ले"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्टिंग कसे काम करते"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करा"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कंपॅटिबल ब्लूटूथ डिव्‍हाइस असलेले तुमच्या जवळपासचे लोक हे तुम्ही ब्रॉडकास्ट करत असलेला मीडिया ऐकू शकतात"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ही स्क्रीन बंद होईल"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड करता येण्यासारखे डिव्हाइस अनफोल्ड केले जात आहे"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड करता येण्यासारखे डिव्हाइस आजूबाजूला फ्लिप केले जात आहे"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"स्टायलस बॅटरी कमी आहे"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b0b40962123f..f08f6a654658 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Sempadan bawah <xliff:g id="PERCENT">%1$d</xliff:g> peratus"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Sempadan kiri <xliff:g id="PERCENT">%1$d</xliff:g> peratus"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Sempadan kanan <xliff:g id="PERCENT">%1$d</xliff:g> peratus"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Perakam Skrin"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses rakaman skrin"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pemberitahuan breterusan untuk sesi rakaman skrin"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mainkan <xliff:g id="SONG_NAME">%1$s</xliff:g> daripada <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Buat asal"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Alihkan lebih dekat untuk bermain pada<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan dengan <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk bermain di sini"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kesilapan telah berlaku. Cuba lagi."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Memuatkan"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Kelantangan"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Pembesar Suara &amp; Paparan"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara siaran berfungsi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siarkan"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang berdekatan anda dengan peranti Bluetooth yang serasi boleh mendengar media yang sedang anda siarkan"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Skrin ini akan dimatikan"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Peranti boleh lipat dibuka"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Peranti boleh lipat diterbalikkan"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Bateri stilus lemah"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 2014f5c566c5..9b6e95cbcd53 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"အောက်ခြေအနားသတ် <xliff:g id="PERCENT">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ဘယ်ဘက်အနားသတ် <xliff:g id="PERCENT">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ညာဘက်အနားသတ် <xliff:g id="PERCENT">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ဖန်သားပြင် ရိုက်ကူးမှု"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"စကရင်ရိုက်ကူးမှု အပြီးသတ်နေသည်"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%2$s</xliff:g> တွင် ဖွင့်ပါ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"နောက်ပြန်ရန်"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင်ဖွင့်ရန် အနီးသို့ရွှေ့ပါ"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ဤနေရာတွင်ဖွင့်ရန် <xliff:g id="DEVICENAME">%1$s</xliff:g> အနီးသို့တိုးပါ"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင် ဖွင့်နေသည်"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ဖွင့်နေသည်"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"အသံအတိုးအကျယ်"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"စပီကာနှင့် ဖန်သားပြင်များ"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ထုတ်လွှင့်မှုဆောင်ရွက်ပုံ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ထုတ်လွှင့်ခြင်း"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"အနီးရှိတွဲသုံးနိုင်သော ဘလူးတုသ်သုံးစက် အသုံးပြုသူများက သင်ထုတ်လွှင့်နေသော မီဒီယာကို နားဆင်နိုင်သည်"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ဤဖန်သားပြင်ကို ပိတ်လိုက်မည်"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ခေါက်နိုင်သောစက်ကို ဖြန့်လိုက်သည်"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ခေါက်နိုင်သောစက်ကို တစ်ဘက်သို့ လှန်လိုက်သည်"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"စတိုင်လပ်စ် ဘက်ထရီ အားနည်းနေသည်"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 2b1ebfdb4f27..7cc0a1a9a1ff 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Nedre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Venstre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Høyre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skjermopptaker"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spill av <xliff:g id="SONG_NAME">%1$s</xliff:g> fra <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Angre"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flytt nærmere for å spille av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytt deg nærmere <xliff:g id="DEVICENAME">%1$s</xliff:g> for å spille av her"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Noe gikk galt. Prøv på nytt."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Laster inn"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Høyttalere og skjermer"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Slik fungerer kringkasting"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Kringkasting"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Folk i nærheten med kompatible Bluetooth-enheter kan lytte til mediene du kringkaster"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Denne skjermen slås av"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En sammenleggbar enhet blir brettet ut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En sammenleggbar enhet blir snudd"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Det er lite batteri i pekepennen"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 98fe304a06b4..f8deac686a94 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"फेदबाट <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"बायाँ किनाराबाट <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"दायाँ किनाराबाट <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रिन रेकर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%2$s</xliff:g> मा बजाउनुहोस्"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"अन्डू गर्नुहोस्"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गर्न आफ्नो डिभाइस नजिकै लैजानुहोस्"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"तपाईं यहाँ प्ले गर्न चाहनुहुन्छ भने आफ्नो डिभाइसलाई <xliff:g id="DEVICENAME">%1$s</xliff:g> नजिकै लैजानुहोस्"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"लोड हुँदै छ"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"भोल्युम"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पिकर तथा डिस्प्लेहरू"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"प्रसारण गर्ने सुविधाले कसरी काम गर्छ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"प्रसारण"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कम्प्याटिबल ब्लुटुथ डिभाइस भएका नजिकैका मान्छेहरू तपाईंले प्रसारण गरिरहनुभएको मिडिया सुन्न सक्छन्"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ यो स्क्रिन अफ हुने छ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड गर्न मिल्ने डिभाइस अनफोल्ड गरेको देखाइएको एनिमेसन"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड गर्न मिल्ने डिभाइस यताउता पल्टाएर देखाइएको एनिमेसन"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलसको ब्याट्री लो छ"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index e49b9fac5ccb..7a0b6d3230fc 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ondergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Linkergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Rechtergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Schermopname"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Ongedaan maken"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ga dichter naar <xliff:g id="DEVICENAME">%1$s</xliff:g> toe om af te spelen"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ga dichter bij <xliff:g id="DEVICENAME">%1$s</xliff:g> staan om hier af te spelen"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Houd dichter bij <xliff:g id="DEVICENAME">%1$s</xliff:g> om af te spelen"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Er is iets misgegaan. Probeer het opnieuw."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Laden"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers en schermen"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitzenden werkt"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Uitzending"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mensen bij jou in de buurt met geschikte bluetooth-apparaten kunnen luisteren naar de media die je uitzendt"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Dit scherm gaat uit"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Opvouwbaar apparaat wordt uitgevouwen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Opvouwbaar apparaat wordt gedraaid"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Batterij van stylus bijna leeg"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 71d0822d078b..6a3a282fc436 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ନିମ୍ନ ସୀମାରେଖା <xliff:g id="PERCENT">%1$d</xliff:g> ଶତକଡ଼ା"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ବାମ ସୀମାରେଖା <xliff:g id="PERCENT">%1$d</xliff:g> ଶତକଡ଼ା"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ଡାହାଣ ସୀମାରେଖା <xliff:g id="PERCENT">%1$d</xliff:g> ଶତକଡ଼ା"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ସ୍କ୍ରିନ୍ ରେକର୍ଡର୍"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରି‍ନ୍‍ ରେକର୍ଡ୍‍ ସେସନ୍‍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ରୁ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ପୂର୍ବବତ୍ କରନ୍ତୁ"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚଲାଇବା ପାଇଁ ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ଏଠାରେ ଚଲାଇବା ପାଇଁ <xliff:g id="DEVICENAME">%1$s</xliff:g>ର ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚାଲୁଛି"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ପ୍ଲେ କରିବା ପାଇଁ ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ପ୍ଲେ ହେଉଛି"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"କିଛି ତ୍ରୁଟି ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ଲୋଡ ହେଉଛି"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ଭଲ୍ୟୁମ"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ସ୍ପିକର ଏବଂ ଡିସପ୍ଲେଗୁଡ଼ିକ"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ବ୍ରଡକାଷ୍ଟିଂ କିପରି କାମ କରେ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ବ୍ରଡକାଷ୍ଟ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ଆପଣଙ୍କ ଆଖପାଖର କମ୍ପାଟିବଲ ବ୍ଲୁଟୁଥ ଡିଭାଇସ ଥିବା ଲୋକମାନେ ଆପଣ ବ୍ରଡକାଷ୍ଟ କରୁଥିବା ମିଡିଆ ଶୁଣିପାରିବେ"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ଏହି ସ୍କ୍ରିନ ବନ୍ଦ ହୋଇଯିବ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରାଯାଉଛି"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଫ୍ଲିପ କରାଯାଉଛି"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"ଷ୍ଟାଇଲସ ବେଟେରୀର ଚାର୍ଜ କମ ଅଛି"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index f6ad3ad01bac..c4dd6b455667 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ਹੇਠਾਂ ਦੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ਖੱਬੇ ਪਾਸੇ ਵਾਲੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ਸੱਜੇ ਪਾਸੇ ਵਾਲੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> ਤੋਂ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚਲਾਓ"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"ਅਣਕੀਤਾ ਕਰੋ"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਉਣ ਲਈ ਨੇੜੇ ਲਿਜਾਓ"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ਇੱਥੇ ਚਲਾਉਣ ਲਈ <xliff:g id="DEVICENAME">%1$s</xliff:g> ਦੇ ਨੇੜੇ ਜਾਓ"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ਲੋਡ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ਅਵਾਜ਼"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ਸਪੀਕਰ ਅਤੇ ਡਿਸਪਲੇਆਂ"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ਪ੍ਰਸਾਰਨ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ਪ੍ਰਸਾਰਨ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ਅਨੁਰੂਪ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਨਾਲ ਨਜ਼ਦੀਕੀ ਲੋਕ ਤੁਹਾਡੇ ਵੱਲੋਂ ਪ੍ਰਸਾਰਨ ਕੀਤੇ ਜਾ ਰਹੇ ਮੀਡੀਆ ਨੂੰ ਸੁਣ ਸਕਦੇ ਹਨ"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ਇਹ ਸਕ੍ਰੀਨ ਬੰਦ ਹੋ ਜਾਵੇਗੀ"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਖੋਲ੍ਹਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਆਲੇ-ਦੁਆਲੇ ਫਲਿੱਪ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ ਘੱਟ ਹੈ"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7cced9e01ba2..08a7ba15cdfc 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Przycięcie dolnej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Przycięcie lewej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Przycięcie prawej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
@@ -377,7 +381,7 @@
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Podczas udostępniania, nagrywania lub przesyłania treści aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ma dostęp do wszystkiego, co jest widoczne na ekranie lub odtwarzane na urządzeniu. Zachowaj ostrożność w przypadku haseł, danych do płatności, wiadomości i innych informacji poufnych."</string>
<string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Podczas udostępniania, nagrywania lub przesyłania treści aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ma dostęp do wszystkiego, co jest w niej wyświetlane lub odtwarzane. Zachowaj ostrożność w przypadku haseł, danych do płatności, wiadomości i innych informacji poufnych."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Dalej"</string>
- <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Udostępnianie i nagrywanie za pomocą aplikacji"</string>
+ <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Udostępnianie i nagrywanie aplikacji"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Zezwolić tej aplikacji na udostępnianie lub nagrywanie?"</string>
<string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Podczas udostępniania, nagrywania lub przesyłania treści ta aplikacja ma dostęp do wszystkiego, co jest widoczne na ekranie lub odtwarzane na urządzeniu. Zachowaj ostrożność w przypadku haseł, danych do płatności, wiadomości i innych informacji poufnych."</string>
<string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Podczas udostępniania, nagrywania lub przesyłania treści ta aplikacja ma dostęp do wszystkiego, co jest w niej wyświetlane lub odtwarzane. Zachowaj ostrożność w przypadku haseł, danych do płatności, wiadomości i innych informacji poufnych."</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Odtwórz utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> w aplikacji <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Cofnij"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Przysuń się bliżej, aby odtwarzać na urządzeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Zbliż do urządzenia <xliff:g id="DEVICENAME">%1$s</xliff:g>, aby na nim odtwarzać"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Odtwarzam na ekranie <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Coś poszło nie tak. Spróbuj ponownie."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Wczytuję"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Głośność"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Głośniki i wyświetlacze"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak działa transmitowanie"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisja"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osoby w pobliżu ze zgodnymi urządzeniami Bluetooth mogą słuchać transmitowanych przez Ciebie multimediów"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* Ekran się wyłączy"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Składane urządzenie jest rozkładane"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Składane urządzenie jest obracane"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Słaba bateria w rysiku"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 41925480b3ad..fa5e83f37c8c 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Borda inferior em <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Borda esquerda em <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Borda direita em <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Capturas de tela do trabalho são salvas no app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
@@ -450,7 +452,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ele é mantido à vista até que seja liberado. Deslize para cima e mantenha pressionado para liberar."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ele é mantido à vista até que seja liberado. Deslize para cima pressione para liberar."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ela é mantida à vista até que seja liberada. Toque em Início e mantenha essa opção pressionada para liberar."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dados pessoais podem ficar acessíveis (como contatos e conteúdo de e-mail)."</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime os dispositivos para tocar a mídia neste: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Carregando"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta tela vai ser desativada"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ad93343fd081..fbedb3aa1cba 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inferior de <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite esquerdo de <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite direito de <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"As capturas de ecrã do trabalho são guardadas na app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ficheiros"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de ecrã"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"A processar a gravação de ecrã"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação persistente de uma sessão de gravação de ecrã"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduzir <xliff:g id="SONG_NAME">%1$s</xliff:g> a partir da app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Anular"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime-se para reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproduzir aqui"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo correu mal. Tente novamente."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"A carregar"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altifalantes e ecrãs"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmissão"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas de si com dispositivos Bluetooth compatíveis podem ouvir o conteúdo multimédia que está a transmitir"</string>
@@ -1015,5 +1019,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Este ecrã vai ser desligado"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável a ser desdobrado"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável a ser virado ao contrário"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da caneta stylus fraca"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de bateria restante"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ligue a caneta stylus a um carregador"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 41925480b3ad..fa5e83f37c8c 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Borda inferior em <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Borda esquerda em <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Borda direita em <xliff:g id="PERCENT">%1$d</xliff:g> por cento"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Capturas de tela do trabalho são salvas no app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
@@ -450,7 +452,7 @@
<string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ele é mantido à vista até que seja liberado. Deslize para cima e mantenha pressionado para liberar."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ele é mantido à vista até que seja liberado. Deslize para cima pressione para liberar."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ela é mantida à vista até que seja liberada. Toque em Início e mantenha essa opção pressionada para liberar."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dados pessoais podem ficar acessíveis (como contatos e conteúdo de e-mail)."</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Aproxime os dispositivos para tocar a mídia neste: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Carregando"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta tela vai ser desativada"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e4a1b0bcf2e0..deef0762f4d8 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Marginea de jos la <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Marginea stângă la <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Marginea dreaptă la <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder pentru ecran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificare în curs pentru o sesiune de înregistrare a ecranului"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Redă <xliff:g id="SONG_NAME">%1$s</xliff:g> în <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Anulează"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Apropie-te pentru a reda pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Apropie-te de <xliff:g id="DEVICENAME">%1$s</xliff:g> ca să redai acolo"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"A apărut o eroare. Încearcă din nou."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Se încarcă"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verifică aplicația"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Difuzoare și afișaje"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cum funcționează transmisia"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmite"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Persoanele din apropiere cu dispozitive Bluetooth compatibile pot asculta conținutul pe care îl transmiți"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Acest ecran se va dezactiva"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispozitiv pliabil care este desfăcut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispozitiv pliabil care este întors"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Nivelul bateriei creionului este scăzut"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9b4975e712e6..97d0d70c4a8c 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Граница снизу: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Граница слева: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Граница справа: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Запись видео с экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Воспроизвести медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Отменить"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Чтобы начать трансляцию на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", подойдите к нему ближе."</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Для воспроизведения на этом устройстве подойдите ближе к другому (<xliff:g id="DEVICENAME">%1$s</xliff:g>)."</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Произошла ошибка. Повторите попытку."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Загрузка…"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Громкость"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Колонки и дисплеи"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работают трансляции"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляция"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Находящиеся рядом с вами люди с совместимыми устройствами Bluetooth могут слушать медиафайлы, которые вы транслируете."</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Этот экран отключится"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складное устройство в разложенном виде"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перевернутое складное устройство"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Низкий заряд батареи стилуса"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 91ed10f66e1d..63acd771f61f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"පහළ සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"වම් සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"දකුණු සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"තිර රෙකෝඩරය"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> වෙතින් වාදනය කරන්න"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"පසුගමනය කරන්න"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කිරීමට වඩාත් ළං වන්න"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"මෙහි ක්‍රීඩා කිරීමට <xliff:g id="DEVICENAME">%1$s</xliff:g> වෙත වඩා සමීප වන්න"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"යම් දෙයක් වැරදිණි. නැවත උත්සාහ කරන්න."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"පූරණය වේ"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"අක්‍රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"හඬ පරිමාව"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ස්පීකර් සහ සංදර්ශක"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"විකාශනය ක්‍රියා කරන ආකාරය"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"විකාශනය"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ගැළපෙන බ්ලූටූත් උපාංග සහිත ඔබ අවට සිටින පුද්ගලයින්ට ඔබ විකාශනය කරන මාධ්‍යයට සවන් දිය හැකිය"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ මෙම තිරය ක්‍රියා විරහිත වනු ඇත"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"දිග හැරෙමින් පවතින නැමිය හැකි උපාංගය"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"වටා පෙරළෙමින් තිබෙන නැමිය හැකි උපාංගය"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"පන්හිඳ බැටරිය අඩුයි"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 4c3d8b816347..5a5d87a320ce 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> %% dolnej hranice"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> %% ľavej hranice"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> %% pravej hranice"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string>
@@ -375,9 +379,9 @@
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Celá obrazovka"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Jedna aplikácia"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Počas zdieľania, nahrávania alebo prenosu bude mať <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> prístup k všetkému na obrazovke, prípadne k obsahu, ktorý sa bude v zariadení prehrávať. Preto venujte zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Počas zdieľania, nahrávania alebo prenosu bude mať aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> prístup k všetkému obsahu, ktorý sa v nej bude zobrazovať alebo prehrávať. Preto venujte zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Keď zdieľate, nahrávate alebo prenášate nejakú aplikáciu, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> má prístup k všetkému obsahu, ktorý sa v aplikácii zobrazuje alebo prehráva. Dajte preto pozor na heslá, platobné údaje, osobné správy a iné citlivé údaje."</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Pokračovať"</string>
- <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Aplikácia na zdieľanie alebo nahrávanie"</string>
+ <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Vyberte aplikáciu, ktorú chcete zdieľať alebo nahrávať"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Chcete povoliť tejto aplikácii zdieľať alebo nahrávať?"</string>
<string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"Počas zdieľania, nahrávania alebo prenosu bude mať táto aplikácia prístup k všetkému na obrazovke, prípadne k obsahu, ktorý sa bude v zariadení prehrávať. Venujte preto zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string>
<string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"Počas zdieľania, nahrávania alebo prenosu bude mať táto aplikácia prístup k všetkému obsahu, ktorý sa v nej bude zobrazovať alebo prehrávať. Venujte preto zvýšenú pozornosť heslám, platobným údajom, správam či ďalším citlivým údajom."</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Späť"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa k nemu"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa k nemu"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Niečo sa pokazilo. Skúste to znova."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Načítava sa"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hlasitosť"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Reproduktory a obrazovky"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ako vysielanie funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysielanie"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ľudia v okolí s kompatibilnými zariadeniami s rozhraním Bluetooth si môžu vypočuť médiá, ktoré vysielate"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Táto obrazovka sa vypne"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozloženie skladacieho zariadenia"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Prevrátenie skladacieho zariadenia"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stav batérie dotykového pera je nízky"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index df5dcb9059df..c16bf230a9b3 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Meja spodaj <xliff:g id="PERCENT">%1$d</xliff:g> odstotkov"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Meja levo <xliff:g id="PERCENT">%1$d</xliff:g> odstotkov"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Meja desno <xliff:g id="PERCENT">%1$d</xliff:g> odstotkov"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Snemalnik zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Nenehno obveščanje o seji snemanja zaslona"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Razveljavi"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Za predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> bolj približajte telefon."</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približajte napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> za predvajanje v tej napravi"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Za predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> bolj približajte telefon"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Prišlo je do napake. Poskusite znova."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Nalaganje"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Glasnost"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvočniki in zasloni"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako deluje oddajanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Oddajanje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osebe v bližini z združljivo napravo Bluetooth lahko poslušajo predstavnost, ki jo oddajate."</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ta zaslon se bo izklopil."</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Razpiranje zložljive naprave"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Obračanje zložljive naprave"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Skoraj prazna baterija pisala"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index ad2e596f849c..e9a6e8c9efb4 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Kufiri i poshtëm <xliff:g id="PERCENT">%1$d</xliff:g> për qind"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kufiri i majtë <xliff:g id="PERCENT">%1$d</xliff:g> për qind"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Kufiri i djathtë <xliff:g id="PERCENT">%1$d</xliff:g> për qind"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Regjistruesi i ekranit"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Regjistrimi i ekranit po përpunohet"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Njoftim i vazhdueshëm për një seancë regjistrimi të ekranit"</string>
@@ -372,7 +376,7 @@
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Do të fillosh regjistrimin ose transmetimin?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Fillo regjistrimin ose transmetimin me <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Të lejohet <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> të shpërndajë ose regjistrojë?"</string>
- <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Ekran i plotë"</string>
+ <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Të gjithë ekranin"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Vetëm një aplikacion"</string>
<string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Gjatë shpërndarjes, regjistrimit ose transmetimit, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në pajisjen tënde. Prandaj ki kujdes me fjalëkalimet, detajet e pagesës, mesazhet ose informacione të tjera të ndjeshme."</string>
<string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Gjatë shpërndarjes, regjistrimit ose transmetimit të një aplikacioni, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në atë aplikacion. Prandaj, ki kujdes me fjalëkalimet, detajet e pagesës, mesazhet ose informacione të tjera të ndjeshme."</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Luaj <xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Zhbëj"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Afrohu për të luajtur në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Afrohu te <xliff:g id="DEVICENAME">%1$s</xliff:g> për ta luajtur këtu"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Ndodhi një gabim. Provo përsëri."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Po ngarkohet"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumi"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altoparlantët dhe ekranet"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Si funksionon transmetimi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmetimi"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personat në afërsi me ty me pajisje të përputhshme me Bluetooth mund të dëgjojnë median që ti po transmeton"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ky ekran do të fiket"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Pajisja e palosshme duke u hapur"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Pajisja e palosshme duke u rrotulluar"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Bateria e stilolapsit në nivel të ulët"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index ef6bb4597104..153ebbf3948b 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Доња ивица <xliff:g id="PERCENT">%1$d</xliff:g> посто"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Лева ивица <xliff:g id="PERCENT">%1$d</xliff:g> посто"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Десна ивица <xliff:g id="PERCENT">%1$d</xliff:g> посто"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пустите <xliff:g id="SONG_NAME">%1$s</xliff:g> из апликације <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Опозови"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Приближите да бисте пуштали музику на: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближите се уређају <xliff:g id="DEVICENAME">%1$s</xliff:g> да бисте на њему пуштали"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пушта се на уређају <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Дошло је до грешке. Пробајте поново."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Учитава се"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Звук"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Звучници и екрани"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционише емитовање"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитовање"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Људи у близини са компатибилним Bluetooth уређајима могу да слушају медијски садржај који емитујете"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Овај екран ће се искључити"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Уређај на преклоп се отвара"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Уређај на преклоп се обрће"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Низак ниво батерије писаљке"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c98273926204..38c7719c13ae 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Nedre gräns: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vänster gräns: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Höger gräns: <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Jobbskärmbilder sparas i <xliff:g id="APP">%1$s</xliff:g>-appen"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Filer"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skärminspelare"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandlar skärminspelning"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Avisering om att skärminspelning pågår"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spela upp <xliff:g id="SONG_NAME">%1$s</xliff:g> från <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Ångra"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Flytta närmare för att spela upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytta dig närmare <xliff:g id="DEVICENAME">%1$s</xliff:g> om du vill spela här"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Något gick fel. Försök igen."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Läser in"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"surfplatta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volym"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Högtalare och skärmar"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Förslag på enheter"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Så fungerar utsändning"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Utsändning"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i närheten med kompatibla Bluetooth-enheter kan lyssna på medieinnehåll som du sänder ut"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Den här skärmen inaktiveras"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En vikbar enhet viks upp"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En vikbar enhet vänds"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"E-pennans batterinivå är låg"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 5e33bf4d82fc..e43acb8533ee 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Mpaka wa sehemu ya chini wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Mpaka wa sehemu ya kushoto wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Mpaka wa sehemu ya kulia wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Kinasa Skrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> katika <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Tendua"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Sogea karibu ili ucheze kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sogeza karibu na <xliff:g id="DEVICENAME">%1$s</xliff:g> ili kucheza hapa"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Sogeza karibu ili ucheze kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Hitilafu fulani imetokea. Jaribu tena."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Inapakia"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Sauti"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Spika na Skrini"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jinsi utangazaji unavyofanya kazi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Tangaza"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Watu walio karibu nawe wenye vifaa oanifu vya Bluetooth wanaweza kusikiliza maudhui unayoyatangaza"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Skrini hii itajizima"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Kifaa kinachokunjwa kikikunjuliwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Kifaa kinachokunjwa kikigeuzwa"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Chaji ya betri ya Stylus imepungua"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 6c7cab51f440..5d78e4e1a44c 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -28,6 +28,7 @@
<!-- QS-->
<dimen name="qs_panel_padding_top">16dp</dimen>
+ <dimen name="qs_panel_padding">24dp</dimen>
<dimen name="qs_content_horizontal_padding">24dp</dimen>
<dimen name="qs_horizontal_margin">24dp</dimen>
<!-- in split shade qs_tiles_page_horizontal_margin should be equal of qs_horizontal_margin/2,
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index f4434e8d0044..ea3c012afc43 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -36,4 +36,15 @@
<integer name="qs_security_footer_maxLines">1</integer>
<bool name="config_use_large_screen_shade_header">true</bool>
+
+ <!-- A collection of defaults for the quick affordances on the lock screen. Each item must be a
+ string with two parts: the ID of the slot and the comma-delimited list of affordance IDs,
+ separated by a colon ':' character. For example: <item>bottom_end:home,wallet</item>. The
+ default is displayed by System UI as long as the user hasn't made a different choice for that
+ slot. If the user did make a choice, even if the choice is the "None" option, the default is
+ ignored. -->
+ <string-array name="config_keyguardQuickAffordanceDefaults" translatable="false">
+ <item>bottom_start:home</item>
+ <item>bottom_end:create_note</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 9bc0dde49b4c..db7fb48a4ac4 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -30,10 +30,6 @@
<!-- Margin on the left side of the carrier text on Keyguard -->
<dimen name="keyguard_carrier_text_margin">24dp</dimen>
- <!-- The width/height of the phone/camera/unlock icon on keyguard. -->
- <dimen name="keyguard_affordance_height">80dp</dimen>
- <dimen name="keyguard_affordance_width">120dp</dimen>
-
<!-- Screen pinning request width -->
<dimen name="screen_pinning_request_width">400dp</dimen>
<!-- Screen pinning request bottom button circle widths -->
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6e14c2630a03..cc58ddb35c36 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"கீழ் எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"இடது எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"வலது எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ஸ்கிரீன் ரெக்கார்டர்"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> பாடலை <xliff:g id="APP_LABEL">%2$s</xliff:g> ஆப்ஸில் பிளேசெய்"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"செயல்தவிர்"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் இயக்க உங்கள் சாதனத்தை அருகில் எடுத்துச் செல்லுங்கள்"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"இங்கு பிளே செய்ய உங்கள் சாதனத்தை <xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்திற்கு அருகில் நகர்த்துங்கள்"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"ஏற்றுகிறது"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ஒலியளவு"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ஸ்பீக்கர்கள் &amp; டிஸ்ப்ளேக்கள்"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"பிராட்காஸ்ட் எவ்வாறு செயல்படுகிறது?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"பிராட்காஸ்ட்"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"நீங்கள் பிராட்காஸ்ட் செய்யும் மீடியாவை அருகிலுள்ளவர்கள் இணக்கமான புளூடூத் சாதனங்கள் மூலம் கேட்கலாம்"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ இந்தத் திரை ஆஃப் ஆகிவிடும்"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"மடக்கத்தக்க சாதனம் திறக்கப்படுகிறது"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"மடக்கத்தக்க சாதனம் ஃபிளிப் செய்யப்பட்டு திருப்பப்படுகிறது"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"ஸ்டைலஸின் பேட்டரி குறைவாக உள்ளது"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index d4e458f78e28..1df7542232a5 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"దిగువ సరిహద్దు <xliff:g id="PERCENT">%1$d</xliff:g> శాతం"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ఎడమ వైపు సరిహద్దు <xliff:g id="PERCENT">%1$d</xliff:g> శాతం"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"కుడి వైపు సరిహద్దు <xliff:g id="PERCENT">%1$d</xliff:g> శాతం"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"వర్క్ స్క్రీన్‌షాట్‌లు <xliff:g id="APP">%1$s</xliff:g> యాప్‌లో సేవ్ చేయబడతాయి"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ఫైల్స్"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"స్క్రీన్ రికార్డర్"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్‌గోయింగ్ నోటిఫికేషన్"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> నుండి <xliff:g id="SONG_NAME">%1$s</xliff:g>‌ను ప్లే చేయండి"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"చర్య రద్దు"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>‌లో ప్లే చేయడానికి దగ్గరగా వెళ్లండి"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ఇక్కడ ప్లే చేయడానికి <xliff:g id="DEVICENAME">%1$s</xliff:g>కి దగ్గరగా వెళ్లండి"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"లోడ్ అవుతోంది"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"టాబ్లెట్"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ఇన్‌యాక్టివ్, యాప్ చెక్ చేయండి"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"వాల్యూమ్"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"స్పీకర్‌లు &amp; డిస్‌ప్లేలు"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"సూచించబడిన పరికరాలు"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ప్రసారం కావడం అనేది ఎలా పని చేస్తుంది"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ప్రసారం"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"మీకు సమీపంలో ఉన్న వ్యక్తులు అనుకూలత ఉన్న బ్లూటూత్ పరికరాలతో మీరు ప్రసారం చేస్తున్న మీడియాను వినగలరు"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ ఈ స్క్రీన్ ఆఫ్ అవుతుంది"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"మడవగల పరికరం విప్పబడుతోంది"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"మడవగల పరికరం చుట్టూ తిప్పబడుతోంది"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"తక్కువ స్టైలస్ బ్యాటరీ"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f8a16bd26483..771a906bc6ec 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ขอบเขตด้านล่าง <xliff:g id="PERCENT">%1$d</xliff:g> เปอร์เซ็นต์"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ขอบเขตด้านซ้าย <xliff:g id="PERCENT">%1$d</xliff:g> เปอร์เซ็นต์"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ขอบเขตด้านขวา <xliff:g id="PERCENT">%1$d</xliff:g> เปอร์เซ็นต์"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"ภาพหน้าจองานจะบันทึกอยู่ในแอป <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ไฟล์"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมบันทึกหน้าจอ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
@@ -849,12 +851,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> จาก <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"เลิกทำ"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"ขยับเข้ามาใกล้ขึ้นเพื่อเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ขยับไปใกล้ <xliff:g id="DEVICENAME">%1$s</xliff:g> มากขึ้นเพื่อเล่นที่นี่"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"ขยับไปใกล้มากขึ้นเพื่อเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"เกิดข้อผิดพลาด โปรดลองอีกครั้ง"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"กำลังโหลด"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"แท็บเล็ต"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ระดับเสียง"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ลำโพงและจอแสดงผล"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"อุปกรณ์ที่แนะนำ"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"วิธีการทำงานของการออกอากาศ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ประกาศ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ผู้ที่อยู่ใกล้คุณและมีอุปกรณ์บลูทูธที่รองรับสามารถรับฟังสื่อที่คุณกำลังออกอากาศได้"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ หน้าจอนี้จะปิดไป"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"อุปกรณ์ที่พับได้กำลังกางออก"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"อุปกรณ์ที่พับได้กำลังพลิกไปมา"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"แบตเตอรี่สไตลัสเหลือน้อย"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3578aa78c96b..aa58d00df76a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> (na) porsyento sa hangganan sa ibaba"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> (na) porsyento sa hangganan sa kaliwa"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> (na) porsyento sa hangganan sa kanan"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Naka-save ang mga screenshot sa trabaho sa <xliff:g id="APP">%1$s</xliff:g> app"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Mga File"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder ng Screen"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pinoproseso screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Kasalukuyang notification para sa session ng pag-record ng screen"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"I-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"I-undo"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Lumapit pa para mag-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Lumapit sa <xliff:g id="DEVICENAME">%1$s</xliff:g> para mag-play rito"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Nagkaproblema. Subukan ulit."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Naglo-load"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Mga Speaker at Display"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Mga Iminumungkahing Device"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Paano gumagana ang pag-broadcast"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Makakapakinig ang mga taong malapit sa iyo na may mga compatible na Bluetooth device sa media na bino-broadcast mo"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Mag-o-off ang screen na ito"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ina-unfold na foldable na device"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Fini-flip na foldable na device"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Paubos na ang baterya ng stylus"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 64431ad25980..2ee29cf925a9 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alt sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Sol sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Sağ sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> uygulamasından <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Geri al"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında çalmak için yaklaşın"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oynatmak için <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaklaşın"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatmak için yaklaşın"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatılıyor"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Bir sorun oldu. Tekrar deneyin."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Yükleme"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ses düzeyi"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hoparlörler ve Ekranlar"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayınlamanın işleyiş şekli"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Anons"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Yakınınızda ve uyumlu Bluetooth cihazları olan kişiler yayınladığınız medya içeriğini dinleyebilir"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ * Bu ekran kapatılacak"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Katlanabilir cihaz açılıyor"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Katlanabilir cihaz döndürülüyor"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Ekran kaleminin pil seviyesi düşük"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9eba61007965..ae22d087f07e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Знизу на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Зліва на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Справа на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Запис відео з екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Увімкнути пісню \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" у додатку <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Відмінити"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Щоб відтворити контент на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>, наблизьтеся до нього"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Наблизьтеся до пристрою <xliff:g id="DEVICENAME">%1$s</xliff:g>, щоб відтворити медіафайли на ньому"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Сталася помилка. Повторіть спробу."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Завантаження"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Гучність"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Колонки й екрани"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як працює трансляція"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляція"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Люди поблизу, які мають сумісні пристрої з Bluetooth, можуть слухати медіаконтент, який ви транслюєте."</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Цей екран вимкнеться"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Розкладний пристрій у розкладеному стані"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Розкладний пристрій обертається"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Низький заряд акумулятора стилуса"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index cfcdeca3a2c9..f02797b6c4ae 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"نیچے کا احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"بایاں احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"دایاں احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"اسکرین ریکارڈر"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string>
@@ -849,11 +853,13 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> سے <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"کالعدم کریں"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چلانے کے لیے قریب کریں"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"یہاں چلانے کے ليے <xliff:g id="DEVICENAME">%1$s</xliff:g> کے قریب جائیں"</string>
- <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"‫<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چلانے کے لیے قریب کریں"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
+ <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"‫<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"کچھ غلط ہوگیا۔ پھر کوشش کریں۔"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"لوڈ ہو رہا ہے"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"والیوم"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"اسپیکرز اور ڈسپلیز"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"براڈکاسٹنگ کیسے کام کرتا ہے"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"براڈکاسٹ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"موافق بلوٹوتھ آلات کے ساتھ آپ کے قریبی لوگ آپ کے نشر کردہ میڈیا کو سن سکتے ہیں"</string>
@@ -1015,5 +1023,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ یہ اسکرین آف ہو جائے گی"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"فولڈ ہونے والے آلے کو کھولا جا رہا ہے"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"فولڈ ہونے والے آلے کو گھمایا جا رہا ہے"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"اسٹائلس بیٹری کم ہے"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> بیٹری باقی ہے"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"اپنے اسٹائلس کو چارجر منسلک کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 83085190c1fa..0d5ad6082831 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Quyi chegara <xliff:g id="PERCENT">%1$d</xliff:g> foiz"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Chap chegara <xliff:g id="PERCENT">%1$d</xliff:g> foiz"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Oʻng chegara <xliff:g id="PERCENT">%1$d</xliff:g> foiz"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"Ish skrinshotlari <xliff:g id="APP">%1$s</xliff:g> ilovasida saqlanadi"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fayllar"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string>
@@ -849,12 +851,12 @@
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etish: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Qaytarish"</string>
- <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g>da ijro etish uchun yaqinroq keling"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Bu yerda ijro qilish uchun <xliff:g id="DEVICENAME">%1$s</xliff:g>qurilmasiga yaqinlashtiring"</string>
+ <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilish uchun unga yaqinlashing"</string>
+ <string name="media_move_closer_to_end_cast" msgid="7302555909119374738">"Shu yerda ijro qilish uchun <xliff:g id="DEVICENAME">%1$s</xliff:g>ga yaqinroq suring"</string>
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilinmoqda"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Xatolik yuz berdi. Qayta urining."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Yuklanmoqda"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planshet"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string>
@@ -878,6 +880,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Tovush balandligi"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Karnaylar va displeylar"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Taklif qilingan qurilmalar"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Translatsiya qanday ishlaydi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Translatsiya"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Atrofingizdagi mos Bluetooth qurilmasiga ega foydalanuvchilar siz translatsiya qilayotgan mediani tinglay olishadi"</string>
@@ -1015,5 +1018,6 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Bu ekran oʻchiriladi"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Buklanadigan qurilma ochilmoqda"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Buklanadigan qurilma aylantirilmoqda"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Stilus batareyasi kam"</string>
+ <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batareya quvvati: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Stilusni quvvat manbaiga ulang"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 80aa82293e65..c2e27d45851e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Cạnh dưới cùng <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Cạnh trái <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Cạnh phải <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Trình ghi màn hình"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Đang xử lý video ghi màn hình"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Thông báo đang diễn ra về phiên ghi màn hình"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Phát <xliff:g id="SONG_NAME">%1$s</xliff:g> trên <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Hủy"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Đưa thiết bị đến gần hơn để phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Di chuyển đến gần <xliff:g id="DEVICENAME">%1$s</xliff:g> hơn để phát tại đây"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Đã xảy ra lỗi. Hãy thử lại."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Đang tải"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Âm lượng"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Loa và màn hình"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cách tính năng truyền hoạt động"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Truyền"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Những người ở gần có thiết bị Bluetooth tương thích có thể nghe nội dung nghe nhìn bạn đang truyền"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Màn hình này sẽ tắt"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Thiết bị có thể gập lại đang được mở ra"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Thiết bị có thể gập lại đang được lật ngược"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Bút cảm ứng bị yếu pin"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index a449e9e332cd..b401a8c9c5bc 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"底部边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左侧边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右侧边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"屏幕录制器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
@@ -374,8 +378,8 @@
<string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"允许 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 分享或录制吗?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"整个屏幕"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"单个应用"</string>
- <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"在您进行分享、录制或投射时,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以访问您的屏幕显示或设备播放的所有内容。因此,请注意保护密码、付款信息、消息或其他敏感信息。"</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"在您进行分享、录制或投射时,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以访问通过此应用显示或播放的所有内容。因此,请注意保护密码、付款信息、消息或其他敏感信息。"</string>
+ <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"当您进行分享、录制或投屏时,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以访问您的屏幕上显示的或设备上播放的所有内容。因此,请注意保护密码、付款信息、消息或其他敏感信息。"</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"当您对一款应用进行分享、录制或投屏时,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以访问该应用中显示或播放的所有内容。因此,请注意保护密码、付款信息、消息或其他敏感信息。"</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"继续"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或录制应用"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"是否允许此应用进行分享或录制?"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"通过<xliff:g id="APP_LABEL">%2$s</xliff:g>播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"撤消"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"若要在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放,请靠近这台设备"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"若要在此设备上播放,请靠近“<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"出了点问题,请重试。"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"正在加载"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"音箱和显示屏"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"广播的运作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"广播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近使用兼容蓝牙设备的用户可以收听您广播的媒体内容"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 此屏幕将会关闭"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展开可折叠设备"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻转可折叠设备"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"触控笔电池电量低"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 4749e3bc9a97..0d54f6b2294b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -91,13 +91,15 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"下方邊界 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左方邊界 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右方邊界 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"工作的螢幕截圖會儲存在「<xliff:g id="APP">%1$s</xliff:g>」應用程式"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"檔案"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕畫面錄影工具"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示錄影畫面工作階段通知"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"要開始錄製嗎?"</string>
<string name="screenrecord_description" msgid="1123231719680353736">"錄影時,Android 系統可擷取螢幕上顯示或裝置播放的任何敏感資料,包括密碼、付款資料、相片、訊息和音訊。"</string>
<string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"錄製整個螢幕畫面"</string>
- <string name="screenrecord_option_single_app" msgid="5954863081500035825">"錄製單一應用程式"</string>
+ <string name="screenrecord_option_single_app" msgid="5954863081500035825">"錄製一個應用程式"</string>
<string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"進行錄製時,Android 可存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他敏感資料。"</string>
<string name="screenrecord_warning_single_app" msgid="7760723997065948283">"錄製應用程式時,Android 可存取在該應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他敏感資料。"</string>
<string name="screenrecord_start_recording" msgid="348286842544768740">"開始錄製"</string>
@@ -373,8 +375,8 @@
<string name="media_projection_dialog_title" msgid="3316063622495360646">"要使用「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」開始錄影或投放嗎?"</string>
<string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"允許 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 分享或錄製嗎?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"整個螢幕畫面"</string>
- <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"單一應用程式"</string>
- <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"進行分享、錄製或投放時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他敏感資料。"</string>
+ <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"一個應用程式"</string>
+ <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"當您分享、錄製或投放應用程式時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可存取在螢幕畫面上顯示或在裝置上播放的所有內容。因此請小心保管密碼、付款資料、訊息或其他敏感資料。"</string>
<string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"進行分享、錄製或投放時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他敏感資料。"</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"繼續"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或錄製應用程式"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"在 <xliff:g id="APP_LABEL">%2$s</xliff:g> 播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近一點"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在此裝置上播放,請靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"載入中"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"平板電腦"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"喇叭和螢幕"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建議的裝置"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近有兼容藍牙裝置的人可收聽您正在廣播的媒體內容"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 此螢幕將關閉"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電量不足"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4972aee02a80..6a78a93dc069 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -91,6 +91,8 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"下方邊界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左側邊界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右側邊界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string>
+ <string name="screenshot_work_profile_notification" msgid="2812417845875653929">"工作的螢幕截圖會儲存在「<xliff:g id="APP">%1$s</xliff:g>」應用程式"</string>
+ <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"檔案"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕錄影器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string>
@@ -374,8 +376,8 @@
<string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"允許 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 分享或錄製?"</string>
<string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"整個螢幕畫面"</string>
<string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"單一應用程式"</string>
- <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"進行分享、錄製或投放時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
- <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"進行分享、錄製或投放應用程式時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取在該應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+ <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"分享、錄製或投放時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"分享、錄製或投放應用程式時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取在應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
<string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"繼續"</string>
<string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或錄製應用程式"</string>
<string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"要允許這個應用程式分享或錄製嗎?"</string>
@@ -850,11 +852,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"透過「<xliff:g id="APP_LABEL">%2$s</xliff:g>」播放〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近一點"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在這部裝置上播放,請移到更靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」的位置"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
- <skip />
+ <string name="media_transfer_loading" msgid="5544017127027152422">"載入中"</string>
+ <string name="media_ttt_default_device_type" msgid="4457646436153370169">"平板電腦"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string>
@@ -878,6 +881,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"喇叭和螢幕"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建議的裝置"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播功能的運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"如果附近的人有相容的藍牙裝置,就可以聽到你正在廣播的媒體內容"</string>
@@ -1015,5 +1019,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ 這麼做會關閉這個螢幕"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開的折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電力不足"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d9cf44b3fe3d..311fe8b99598 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -91,6 +91,10 @@
<string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Iphesenti elingu-<xliff:g id="PERCENT">%1$d</xliff:g> lomngcele ophansi"</string>
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Iphesenti elingu-<xliff:g id="PERCENT">%1$d</xliff:g> lomngcele ongakwesobunxele"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Iphesenti elingu-<xliff:g id="PERCENT">%1$d</xliff:g> lomngcele ongakwesokudla"</string>
+ <!-- no translation found for screenshot_work_profile_notification (2812417845875653929) -->
+ <skip />
+ <!-- no translation found for screenshot_default_files_app_name (8721579578575161912) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Irekhoda yesikrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Isaziso esiqhubekayo seseshini yokurekhoda isikrini"</string>
@@ -850,10 +854,12 @@
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Dlala i-<xliff:g id="SONG_NAME">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
<string name="media_transfer_undo" msgid="1895606387620728736">"Hlehlisa"</string>
<string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Sondeza eduze ukudlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
- <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sondela eduze ne-<xliff:g id="DEVICENAME">%1$s</xliff:g> ukuze udlale lapha"</string>
+ <!-- no translation found for media_move_closer_to_end_cast (7302555909119374738) -->
+ <skip />
<string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="media_transfer_failed" msgid="7955354964610603723">"Kukhona okungahambanga kahle. Zama futhi."</string>
- <!-- no translation found for media_transfer_loading (5544017127027152422) -->
+ <string name="media_transfer_loading" msgid="5544017127027152422">"Iyalayisha"</string>
+ <!-- no translation found for media_ttt_default_device_type (4457646436153370169) -->
<skip />
<string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
@@ -878,6 +884,8 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ivolumu"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Izipikha Neziboniso"</string>
+ <!-- no translation found for media_output_group_title_suggested_device (4157186235837903826) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Indlela ukusakaza okusebenza ngayo"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Sakaza"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Abantu abaseduze nawe abanamadivayisi e-Bluetooth ahambisanayo bangalalela imidiya oyisakazayo"</string>
@@ -1015,5 +1023,8 @@
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Lesi sikrini sizovala"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Idivayisi egoqekayo iyembulwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Idivayisi egoqekayo iphendulwa nxazonke"</string>
- <string name="stylus_battery_low" msgid="7134370101603167096">"Ibhethri le-stylus liphansi"</string>
+ <!-- no translation found for stylus_battery_low_percentage (1620068112350141558) -->
+ <skip />
+ <!-- no translation found for stylus_battery_low_subtitle (3583843128908823273) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 890d96444b04..1ef020643a90 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -762,12 +762,10 @@
<dimen name="go_to_full_shade_appearing_translation">200dp</dimen>
<!-- The width/height of the keyguard bottom area icon view on keyguard. -->
- <dimen name="keyguard_affordance_height">48dp</dimen>
- <dimen name="keyguard_affordance_width">48dp</dimen>
-
<dimen name="keyguard_affordance_fixed_height">48dp</dimen>
<dimen name="keyguard_affordance_fixed_width">48dp</dimen>
<dimen name="keyguard_affordance_fixed_radius">24dp</dimen>
+
<!-- Amount the button should shake when it's not long-pressed for long enough. -->
<dimen name="keyguard_affordance_shake_amplitude">8dp</dimen>
@@ -1089,6 +1087,7 @@
(112 - 40) / 2 = 36dp -->
<dimen name="media_ttt_generic_icon_padding">36dp</dimen>
<dimen name="media_ttt_receiver_vert_translation">40dp</dimen>
+ <dimen name="media_ttt_receiver_icon_bottom_margin">10dp</dimen>
<!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2de16a417d20..066b185c6d1f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1455,10 +1455,10 @@
<string name="notification_conversation_summary_low">No sound or vibration and appears lower in conversation section</string>
<!-- [CHAR LIMIT=150] Notification Importance title: normal importance level summary -->
- <string name="notification_channel_summary_default">May ring or vibrate based on phone settings</string>
+ <string name="notification_channel_summary_default">May ring or vibrate based on device settings</string>
<!-- [CHAR LIMIT=150] Conversation Notification Importance title: normal conversation level, with bubbling summary -->
- <string name="notification_channel_summary_default_with_bubbles">May ring or vibrate based on phone settings. Conversations from <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubble by default.</string>
+ <string name="notification_channel_summary_default_with_bubbles">May ring or vibrate based on device settings. Conversations from <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubble by default.</string>
<!-- [CHAR LIMIT=150] Notification Importance title: automatic importance level summary -->
<string name="notification_channel_summary_automatic">Have the system determine if this notification should make sound or vibration</string>
@@ -2777,4 +2777,25 @@
<string name="stylus_battery_low_percentage"><xliff:g id="percentage" example="16%">%s</xliff:g> battery remaining</string>
<!-- Subtitle for the notification sent when a stylus battery is low. [CHAR LIMIT=none]-->
<string name="stylus_battery_low_subtitle">Connect your stylus to a charger</string>
+
+ <!-- Title for notification of low stylus battery. [CHAR_LIMIT=NONE] -->
+ <string name="stylus_battery_low">Stylus battery low</string>
+
+ <!-- Label for a lock screen shortcut to start the camera in video mode. [CHAR_LIMIT=16] -->
+ <string name="video_camera">Video camera</string>
+
+ <!-- Switch to work profile dialer app for placing a call dialog. -->
+ <!-- Text for Switch to work profile dialog's Title. Switch to work profile dialog guide users to make call from work
+ profile dialer app as it's not possible to make call from current profile due to an admin policy. [CHAR LIMIT=60] -->
+ <string name="call_from_work_profile_title">Can\'t call from this profile</string>
+ <!-- Text for switch to work profile for call dialog to guide users to make call from work
+ profile dialer app as it's not possible to make call from current profile due to an admin policy. [CHAR LIMIT=NONE]
+ -->
+ <string name="call_from_work_profile_text">Your work policy allows you to make phone calls only from the work profile</string>
+ <!-- Label for the button to switch to work profile for placing call. Switch to work profile dialog guide users to make call from work
+ profile dialer app as it's not possible to make call from current profile due to an admin policy.[CHAR LIMIT=60] -->
+ <string name="call_from_work_profile_action">Switch to work profile</string>
+ <!-- Label for the close button on switch to work profile dialog. Switch to work profile dialog guide users to make call from work
+ profile dialer app as it's not possible to make call from current profile due to an admin policy.[CHAR LIMIT=60] -->
+ <string name="call_from_work_profile_close">Close</string>
</resources>
diff --git a/packages/SystemUI/res/xml/large_screen_shade_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml
index 06d425c57577..bf576dc5790b 100644
--- a/packages/SystemUI/res/xml/large_screen_shade_header.xml
+++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,105 +14,73 @@
~ limitations under the License.
-->
-<ConstraintSet
- xmlns:android="http://schemas.android.com/apk/res/android"
+<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/large_screen_header_constraint">
- <Constraint
- android:id="@+id/clock">
+ <Constraint android:id="@+id/clock">
<Layout
android:layout_width="wrap_content"
android:layout_height="0dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/date"
- app:layout_constraintHorizontal_bias="0"
- />
- <Transform
- android:scaleX="1"
- android:scaleY="1"
- />
+ app:layout_constraintStart_toEndOf="@id/begin_guide"
+ app:layout_constraintTop_toTopOf="parent" />
+ <PropertySet android:alpha="1" />
</Constraint>
- <Constraint
- android:id="@+id/date">
+ <Constraint android:id="@+id/date">
<Layout
android:layout_width="wrap_content"
android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/clock"
- app:layout_constraintEnd_toStartOf="@id/carrier_group"
- app:layout_constraintTop_toTopOf="parent"
+ android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="0"
- />
+ app:layout_constraintStart_toEndOf="@id/clock"
+ app:layout_constraintTop_toTopOf="parent" />
+ <PropertySet android:alpha="1" />
</Constraint>
- <Constraint
- android:id="@+id/carrier_group">
+ <Constraint android:id="@+id/carrier_group">
<Layout
- app:layout_constraintWidth_min="48dp"
android:layout_width="0dp"
android:layout_height="0dp"
- app:layout_constrainedWidth="true"
android:layout_gravity="end|center_vertical"
- android:layout_marginStart="8dp"
- app:layout_constraintStart_toEndOf="@id/date"
- app:layout_constraintEnd_toStartOf="@id/statusIcons"
- app:layout_constraintTop_toTopOf="@id/clock"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
- <PropertySet
- android:alpha="1"
- />
+ app:layout_constraintEnd_toStartOf="@id/statusIcons"
+ app:layout_constraintStart_toEndOf="@id/date"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_default="wrap"
+ app:layout_constraintWidth_min="48dp" />
+ <PropertySet android:alpha="1" />
</Constraint>
- <Constraint
- android:id="@+id/statusIcons">
+ <Constraint android:id="@+id/statusIcons">
<Layout
- app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
android:layout_width="wrap_content"
android:layout_height="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintStart_toEndOf="@id/carrier_group"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="@id/clock"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
- <PropertySet
- android:alpha="1"
- />
+ app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/carrier_group"/>
+ <PropertySet android:alpha="1" />
</Constraint>
- <Constraint
- android:id="@+id/batteryRemainingIcon">
+ <Constraint android:id="@+id/batteryRemainingIcon">
<Layout
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintStart_toEndOf="@id/statusIcons"
- app:layout_constraintEnd_toStartOf="@id/privacy_container"
- app:layout_constraintTop_toTopOf="@id/clock"
app:layout_constraintBottom_toBottomOf="parent"
- />
- <PropertySet
- android:alpha="1"
- />
+ app:layout_constraintEnd_toStartOf="@id/privacy_container"
+ app:layout_constraintTop_toTopOf="parent" />
+ <PropertySet android:alpha="1" />
</Constraint>
- <Constraint
- android:id="@+id/privacy_container">
+ <Constraint android:id="@+id/privacy_container">
<Layout
android:layout_width="wrap_content"
android:layout_height="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="@id/date"
- app:layout_constraintBottom_toBottomOf="@id/date"
- app:layout_constraintStart_toEndOf="@id/batteryRemainingIcon"
- app:layout_constraintHorizontal_bias="1"
- />
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/end_guide"
+ app:layout_constraintTop_toTopOf="parent" />
</Constraint>
-
</ConstraintSet> \ No newline at end of file
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index b679cfa145d4..b7d9df9217b2 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -85,6 +85,9 @@ java_library {
static_libs: [
"SystemUI-flag-types",
],
+ optimize: {
+ proguard_flags_files: ["proguard_flags.flags"],
+ },
java_version: "1.8",
min_sdk_version: "current",
}
diff --git a/packages/SystemUI/shared/proguard_flags.flags b/packages/SystemUI/shared/proguard_flags.flags
new file mode 100644
index 000000000000..08859cd8a10f
--- /dev/null
+++ b/packages/SystemUI/shared/proguard_flags.flags
@@ -0,0 +1 @@
+-keep class * implements com.android.systemui.flags.ParcelableFlag \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputDevice.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputDevice.kt
new file mode 100644
index 000000000000..a9a5cf974f95
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputDevice.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.shared.hardware
+
+import android.view.InputDevice
+
+/**
+ * Returns true if [InputDevice] is electronic components to allow a user to use an active stylus in
+ * the host device or a passive stylus is detected by the host device.
+ */
+val InputDevice.isInternalStylusSource: Boolean
+ get() = isAnyStylusSource && !isExternal
+
+/** Returns true if [InputDevice] is an active stylus. */
+val InputDevice.isExternalStylusSource: Boolean
+ get() = isAnyStylusSource && isExternal
+
+/**
+ * Returns true if [InputDevice] supports any stylus source.
+ *
+ * @see InputDevice.isInternalStylusSource
+ * @see InputDevice.isExternalStylusSource
+ */
+val InputDevice.isAnyStylusSource: Boolean
+ get() = supportsSource(InputDevice.SOURCE_STYLUS)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputManager.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputManager.kt
new file mode 100644
index 000000000000..f020b4ec4983
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/hardware/InputManager.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.shared.hardware
+
+import android.hardware.input.InputManager
+import android.view.InputDevice
+
+/**
+ * Gets information about all input devices in the system and returns as a lazy [Sequence].
+ *
+ * For performance reasons, it is preferred to operate atop the returned [Sequence] to ensure each
+ * operation is executed on an element-per-element basis yet customizable.
+ *
+ * For example:
+ * ```kotlin
+ * val stylusDevices = inputManager.getInputDeviceSequence().filter {
+ * it.supportsSource(InputDevice.SOURCE_STYLUS)
+ * }
+ *
+ * val hasInternalStylus = stylusDevices.any { it.isInternal }
+ * val hasExternalStylus = stylusDevices.any { !it.isInternal }
+ * ```
+ *
+ * @return a [Sequence] of [InputDevice].
+ */
+fun InputManager.getInputDeviceSequence(): Sequence<InputDevice> =
+ inputDeviceIds.asSequence().mapNotNull { getInputDevice(it) }
+
+/**
+ * Returns the first [InputDevice] matching the given predicate, or null if no such [InputDevice]
+ * was found.
+ */
+fun InputManager.findInputDevice(predicate: (InputDevice) -> Boolean): InputDevice? =
+ getInputDeviceSequence().find { predicate(it) }
+
+/**
+ * Returns true if [any] [InputDevice] matches with [predicate].
+ *
+ * For example:
+ * ```kotlin
+ * val hasStylusSupport = inputManager.hasInputDevice { it.isStylusSupport() }
+ * val hasStylusPen = inputManager.hasInputDevice { it.isStylusPen() }
+ * ```
+ */
+fun InputManager.hasInputDevice(predicate: (InputDevice) -> Boolean): Boolean =
+ getInputDeviceSequence().any { predicate(it) }
+
+/** Returns true if host device has any [InputDevice] where [InputDevice.isInternalStylusSource]. */
+fun InputManager.hasInternalStylusSource(): Boolean = hasInputDevice { it.isInternalStylusSource }
+
+/** Returns true if host device has any [InputDevice] where [InputDevice.isExternalStylusSource]. */
+fun InputManager.hasExternalStylusSource(): Boolean = hasInputDevice { it.isExternalStylusSource }
+
+/** Returns true if host device has any [InputDevice] where [InputDevice.isAnyStylusSource]. */
+fun InputManager.hasAnyStylusSource(): Boolean = hasInputDevice { it.isAnyStylusSource }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 1c532fe7a529..b8bddd149d9a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -22,6 +22,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.MotionEvent;
+import com.android.internal.util.ScreenshotRequest;
import com.android.systemui.shared.recents.model.Task;
@@ -87,12 +88,6 @@ interface ISystemUiProxy {
void notifyPrioritizedRotation(int rotation) = 25;
/**
- * Handle the provided image as if it was a screenshot.
- */
- void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
- in Insets visibleInsets, in Task.TaskKey task) = 28;
-
- /**
* Notifies to expand notification panel.
*/
void expandNotificationPanel() = 29;
@@ -125,5 +120,10 @@ interface ISystemUiProxy {
*/
void toggleNotificationPanel() = 50;
- // Next id = 51
+ /**
+ * Handle the screenshot request.
+ */
+ void takeScreenshot(in ScreenshotRequest request) = 51;
+
+ // Next id = 52
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 88ce2a74c99d..71cd18dd9703 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -199,7 +199,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK),
+ Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
false, /* notifyForDescendants */
mDoubleLineClockObserver,
UserHandle.USER_ALL
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index d4ca8e34fb32..ea84438bf4ba 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -29,6 +29,9 @@ import android.view.View;
import android.view.View.OnKeyListener;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
+import android.window.OnBackAnimationCallback;
+
+import androidx.annotation.NonNull;
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -394,6 +397,14 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
}
/**
+ * @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
+ */
+ @NonNull
+ public OnBackAnimationCallback getBackCallback() {
+ return mKeyguardSecurityContainerController.getBackCallback();
+ }
+
+ /**
* Allows the media keys to work when the keyguard is showing.
* The media keys should be of no interest to the actual keyguard view(s),
* so intercepting them here should not be of any harm.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5d7a6f122e69..e4f85db3971e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,6 +32,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.START;
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
+import static com.android.systemui.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static java.lang.Integer.max;
@@ -73,6 +74,8 @@ import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
+import android.window.BackEvent;
+import android.window.OnBackAnimationCallback;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
@@ -135,7 +138,9 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
private static final float MIN_DRAG_SIZE = 10;
// How much to scale the default slop by, to avoid accidental drags.
private static final float SLOP_SCALE = 4f;
-
+ @VisibleForTesting
+ // How much the view scales down to during back gestures.
+ static final float MIN_BACK_SCALE = 0.9f;
@VisibleForTesting
KeyguardSecurityViewFlipper mSecurityViewFlipper;
private GlobalSettings mGlobalSettings;
@@ -240,6 +245,33 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
}
};
+ private final OnBackAnimationCallback mBackCallback = new OnBackAnimationCallback() {
+ @Override
+ public void onBackCancelled() {
+ // TODO(b/259608500): Remove once back API auto animates progress to 0 on cancel.
+ resetScale();
+ }
+
+ @Override
+ public void onBackInvoked() { }
+
+ @Override
+ public void onBackProgressed(BackEvent event) {
+ float progress = event.getProgress();
+ // TODO(b/263819310): Update the interpolator to match spec.
+ float scale = MIN_BACK_SCALE
+ + (1 - MIN_BACK_SCALE) * (1 - DECELERATE_QUINT.getInterpolation(progress));
+ setScale(scale);
+ }
+ };
+ /**
+ * @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
+ */
+ @NonNull
+ OnBackAnimationCallback getBackCallback() {
+ return mBackCallback;
+ }
+
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
/**
@@ -736,6 +768,15 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
mViewMode.onDensityOrFontScaleChanged();
}
+ void resetScale() {
+ setScale(1);
+ }
+
+ private void setScale(float scale) {
+ setScaleX(scale);
+ setScaleY(scale);
+ }
+
/**
* Enscapsulates the differences between bouncer modes for the container.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index a72a484fb6f1..57bfe5421049 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -40,7 +40,9 @@ import android.util.Log;
import android.util.Slog;
import android.view.MotionEvent;
import android.view.View;
+import android.window.OnBackAnimationCallback;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
@@ -479,6 +481,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
/** Called when the bouncer changes visibility. */
public void onBouncerVisibilityChanged(@View.Visibility int visibility) {
setBouncerVisible(visibility == View.VISIBLE);
+ if (visibility == View.INVISIBLE) {
+ mView.resetScale();
+ }
}
private void setBouncerVisible(boolean visible) {
@@ -588,6 +593,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
/**
+ * @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
+ */
+ @NonNull
+ OnBackAnimationCallback getBackCallback() {
+ return mView.getBackCallback();
+ }
+
+ /**
* Switches to the given security view unless it's already being shown, in which case
* this is a no-op.
*
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 204f09ee4678..a9695dd62ba4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -86,7 +86,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
@@ -110,7 +109,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
@@ -274,21 +272,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
"com.android.settings", "com.android.settings.FallbackHome");
- /**
- * If true, the system is in the half-boot-to-decryption-screen state.
- * Prudently disable lockscreen.
- */
- public static final boolean CORE_APPS_ONLY;
-
- static {
- try {
- CORE_APPS_ONLY = IPackageManager.Stub.asInterface(
- ServiceManager.getService("package")).isOnlyCoreApps();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
private final Context mContext;
private final UserTracker mUserTracker;
private final KeyguardUpdateMonitorLogger mLogger;
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
new file mode 100644
index 000000000000..249b3fe97d81
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.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.keyguard.logging
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.TrustModel
+import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import javax.inject.Inject
+
+/** Logging helper for trust repository. */
+@SysUISingleton
+class TrustRepositoryLogger
+@Inject
+constructor(
+ @KeyguardUpdateMonitorLog private val logBuffer: LogBuffer,
+) {
+ fun onTrustChanged(
+ enabled: Boolean,
+ newlyUnlocked: Boolean,
+ userId: Int,
+ flags: Int,
+ trustGrantedMessages: List<String>?
+ ) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ bool1 = enabled
+ bool2 = newlyUnlocked
+ int1 = userId
+ int2 = flags
+ str1 = trustGrantedMessages?.joinToString()
+ },
+ {
+ "onTrustChanged enabled: $bool1, newlyUnlocked: $bool2, " +
+ "userId: $int1, flags: $int2, grantMessages: $str1"
+ }
+ )
+ }
+
+ fun trustListenerRegistered() {
+ logBuffer.log(TAG, LogLevel.VERBOSE, "TrustRepository#registerTrustListener")
+ }
+
+ fun trustListenerUnregistered() {
+ logBuffer.log(TAG, LogLevel.VERBOSE, "TrustRepository#unregisterTrustListener")
+ }
+
+ fun trustModelEmitted(value: TrustModel) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = value.userId
+ bool1 = value.isTrusted
+ },
+ { "trustModel emitted: userId: $int1 isTrusted: $bool1" }
+ )
+ }
+
+ fun isCurrentUserTrusted(isCurrentUserTrusted: Boolean) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { bool1 = isCurrentUserTrusted },
+ { "isCurrentUserTrusted emitted: $bool1" }
+ )
+ }
+
+ companion object {
+ const val TAG = "TrustRepositoryLog"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
index fbb909f30121..2c97d62d690e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
@@ -27,6 +27,7 @@ import android.provider.Settings;
import android.util.Log;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.settings.UserTracker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -67,8 +68,8 @@ public class AccessibilityButtonModeObserver extends
}
@Inject
- public AccessibilityButtonModeObserver(Context context) {
- super(context, Settings.Secure.ACCESSIBILITY_BUTTON_MODE);
+ public AccessibilityButtonModeObserver(Context context, UserTracker userTracker) {
+ super(context, userTracker, Settings.Secure.ACCESSIBILITY_BUTTON_MODE);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java
index b32ebccdd7db..53a21b329594 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java
@@ -23,6 +23,7 @@ import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.settings.UserTracker;
import javax.inject.Inject;
@@ -48,8 +49,8 @@ public class AccessibilityButtonTargetsObserver extends
}
@Inject
- public AccessibilityButtonTargetsObserver(Context context) {
- super(context, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
+ public AccessibilityButtonTargetsObserver(Context context, UserTracker userTracker) {
+ super(context, userTracker, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
index e4e0da6a2310..326773fb5bef 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
@@ -27,6 +27,7 @@ import android.provider.Settings;
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.settings.UserTracker;
import java.util.ArrayList;
import java.util.List;
@@ -44,6 +45,7 @@ import java.util.Objects;
public abstract class SecureSettingsContentObserver<T> {
private final ContentResolver mContentResolver;
+ private final UserTracker mUserTracker;
@VisibleForTesting
final ContentObserver mContentObserver;
@@ -52,9 +54,11 @@ public abstract class SecureSettingsContentObserver<T> {
@VisibleForTesting
final List<T> mListeners = new ArrayList<>();
- protected SecureSettingsContentObserver(Context context, String secureSettingsKey) {
+ protected SecureSettingsContentObserver(Context context, UserTracker userTracker,
+ String secureSettingsKey) {
mKey = secureSettingsKey;
mContentResolver = context.getContentResolver();
+ mUserTracker = userTracker;
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
@@ -103,7 +107,7 @@ public abstract class SecureSettingsContentObserver<T> {
* See {@link Settings.Secure}.
*/
public final String getSettingsValue() {
- return Settings.Secure.getStringForUser(mContentResolver, mKey, UserHandle.USER_CURRENT);
+ return Settings.Secure.getStringForUser(mContentResolver, mKey, mUserTracker.getUserId());
}
private void updateValueChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index dab73e9bf289..4c9259889a37 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -35,14 +35,12 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -52,6 +50,7 @@ import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -179,6 +178,7 @@ public class SystemActions implements CoreStartable {
private final SystemActionsBroadcastReceiver mReceiver;
private final Context mContext;
+ private final UserTracker mUserTracker;
private final Optional<Recents> mRecentsOptional;
private Locale mLocale;
private final AccessibilityManager mA11yManager;
@@ -190,11 +190,13 @@ public class SystemActions implements CoreStartable {
@Inject
public SystemActions(Context context,
+ UserTracker userTracker,
NotificationShadeWindowController notificationShadeController,
ShadeController shadeController,
Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
Optional<Recents> recentsOptional) {
mContext = context;
+ mUserTracker = userTracker;
mShadeController = shadeController;
mRecentsOptional = recentsOptional;
mReceiver = new SystemActionsBroadcastReceiver();
@@ -343,6 +345,7 @@ public class SystemActions implements CoreStartable {
/**
* Register a system action.
+ *
* @param actionId the action ID to register.
*/
public void register(int actionId) {
@@ -440,6 +443,7 @@ public class SystemActions implements CoreStartable {
/**
* Unregister a system action.
+ *
* @param actionId the action ID to unregister.
*/
public void unregister(int actionId) {
@@ -475,7 +479,8 @@ public class SystemActions implements CoreStartable {
}
private void handleNotifications() {
- mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::animateExpandNotificationsPanel);
+ mCentralSurfacesOptionalLazy.get().ifPresent(
+ CentralSurfaces::animateExpandNotificationsPanel);
}
private void handleQuickSettings() {
@@ -507,7 +512,7 @@ public class SystemActions implements CoreStartable {
private void handleTakeScreenshot() {
ScreenshotHelper screenshotHelper = new ScreenshotHelper(mContext);
- screenshotHelper.takeScreenshot(WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
+ screenshotHelper.takeScreenshot(
SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null);
}
@@ -525,7 +530,7 @@ public class SystemActions implements CoreStartable {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
final String chooserClassName = AccessibilityButtonChooserActivity.class.getName();
intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ mContext.startActivityAsUser(intent, mUserTracker.getUserHandle());
}
private void handleAccessibilityShortcut() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
index 9af83003d26f..7441e034f6f9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
@@ -43,6 +43,7 @@ import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.util.settings.SecureSettings;
import java.util.List;
@@ -60,6 +61,7 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
private static final float DEFAULT_POSITION_Y_PERCENT = 0.9f;
private final Context mContext;
+ private final SecureSettings mSecureSettings;
private final AccessibilityFloatingMenuView mMenuView;
private final MigrationTooltipView mMigrationTooltipView;
private final DockTooltipView mDockTooltipView;
@@ -77,7 +79,7 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- mMenuView.setSizeType(getSizeType(mContext));
+ mMenuView.setSizeType(getSizeType());
}
};
@@ -85,8 +87,8 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext),
- getOpacityValue(mContext));
+ mMenuView.updateOpacityWith(isFadeEffectEnabled(),
+ getOpacityValue());
}
};
@@ -98,16 +100,19 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
}
};
- public AccessibilityFloatingMenu(Context context) {
+ public AccessibilityFloatingMenu(Context context, SecureSettings secureSettings) {
mContext = context;
+ mSecureSettings = secureSettings;
mMenuView = new AccessibilityFloatingMenuView(context, getPosition(context));
mMigrationTooltipView = new MigrationTooltipView(mContext, mMenuView);
mDockTooltipView = new DockTooltipView(mContext, mMenuView);
}
@VisibleForTesting
- AccessibilityFloatingMenu(Context context, AccessibilityFloatingMenuView menuView) {
+ AccessibilityFloatingMenu(Context context, SecureSettings secureSettings,
+ AccessibilityFloatingMenuView menuView) {
mContext = context;
+ mSecureSettings = secureSettings;
mMenuView = menuView;
mMigrationTooltipView = new MigrationTooltipView(mContext, mMenuView);
mDockTooltipView = new DockTooltipView(mContext, mMenuView);
@@ -130,10 +135,10 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
mMenuView.show();
mMenuView.onTargetsChanged(targetList);
- mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext),
- getOpacityValue(mContext));
- mMenuView.setSizeType(getSizeType(mContext));
- mMenuView.setShapeType(getShapeType(mContext));
+ mMenuView.updateOpacityWith(isFadeEffectEnabled(),
+ getOpacityValue());
+ mMenuView.setSizeType(getSizeType());
+ mMenuView.setShapeType(getShapeType());
mMenuView.setOnDragEndListener(this::onDragEnd);
showMigrationTooltipIfNecessary();
@@ -170,17 +175,17 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
// Migration tooltip was the android S feature. It's just used on the Android version from R
// to S. In addition, it only shows once.
private void showMigrationTooltipIfNecessary() {
- if (isMigrationTooltipPromptEnabled(mContext)) {
+ if (isMigrationTooltipPromptEnabled()) {
mMigrationTooltipView.show();
- Settings.Secure.putInt(mContext.getContentResolver(),
+ mSecureSettings.putInt(
ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT, /* disabled */ 0);
}
}
- private static boolean isMigrationTooltipPromptEnabled(Context context) {
- return Settings.Secure.getInt(
- context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
+ private boolean isMigrationTooltipPromptEnabled() {
+ return mSecureSettings.getInt(
+ ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED) == /* enabled */ 1;
}
@@ -212,57 +217,61 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
}
}
- private static boolean isFadeEffectEnabled(Context context) {
- return Settings.Secure.getInt(
- context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
+ private boolean isFadeEffectEnabled() {
+ return mSecureSettings.getInt(
+ ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
DEFAULT_FADE_EFFECT_IS_ENABLED) == /* enabled */ 1;
}
- private static float getOpacityValue(Context context) {
- return Settings.Secure.getFloat(
- context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_OPACITY,
+ private float getOpacityValue() {
+ return mSecureSettings.getFloat(
+ ACCESSIBILITY_FLOATING_MENU_OPACITY,
DEFAULT_OPACITY_VALUE);
}
- private static int getSizeType(Context context) {
- return Settings.Secure.getInt(
- context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_SIZE, SizeType.SMALL);
+ private int getSizeType() {
+ return mSecureSettings.getInt(
+ ACCESSIBILITY_FLOATING_MENU_SIZE, SizeType.SMALL);
}
- private static int getShapeType(Context context) {
- return Settings.Secure.getInt(
- context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_ICON_TYPE,
+ private int getShapeType() {
+ return mSecureSettings.getInt(
+ ACCESSIBILITY_FLOATING_MENU_ICON_TYPE,
ShapeType.OVAL);
}
private void registerContentObservers() {
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
/* notifyForDescendants */ false, mContentObserver,
UserHandle.USER_CURRENT);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
+ /* notifyForDescendants */ false, mContentObserver,
+ UserHandle.USER_CURRENT);
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
/* notifyForDescendants */ false, mSizeContentObserver,
UserHandle.USER_CURRENT);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED),
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
/* notifyForDescendants */ false, mFadeOutContentObserver,
UserHandle.USER_CURRENT);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY,
/* notifyForDescendants */ false, mFadeOutContentObserver,
UserHandle.USER_CURRENT);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES),
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
/* notifyForDescendants */ false,
mEnabledA11yServicesContentObserver, UserHandle.USER_CURRENT);
}
private void unregisterContentObservers() {
- mContext.getContentResolver().unregisterContentObserver(mContentObserver);
- mContext.getContentResolver().unregisterContentObserver(mSizeContentObserver);
- mContext.getContentResolver().unregisterContentObserver(mFadeOutContentObserver);
- mContext.getContentResolver().unregisterContentObserver(
+ mSecureSettings.unregisterContentObserver(mContentObserver);
+ mSecureSettings.unregisterContentObserver(mSizeContentObserver);
+ mSecureSettings.unregisterContentObserver(mFadeOutContentObserver);
+ mSecureSettings.unregisterContentObserver(
mEnabledA11yServicesContentObserver);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index 403941f8e639..6216b8931b34 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -31,6 +31,7 @@ import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
@@ -44,6 +45,7 @@ public class AccessibilityFloatingMenuController implements
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final SecureSettings mSecureSettings;
private Context mContext;
@VisibleForTesting
@@ -85,11 +87,13 @@ public class AccessibilityFloatingMenuController implements
public AccessibilityFloatingMenuController(Context context,
AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
- KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecureSettings secureSettings) {
mContext = context;
mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mSecureSettings = secureSettings;
mIsKeyguardVisible = false;
}
@@ -159,7 +163,7 @@ public class AccessibilityFloatingMenuController implements
private void showFloatingMenu() {
if (mFloatingMenu == null) {
- mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+ mFloatingMenu = new AccessibilityFloatingMenu(mContext, mSecureSettings);
}
mFloatingMenu.show();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 7c2673c31bf5..da2e28c5522f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -35,8 +35,10 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
@@ -119,6 +121,8 @@ public class AssistManager {
private final UiController mUiController;
protected final Lazy<SysUiState> mSysUiState;
protected final AssistLogger mAssistLogger;
+ private final UserTracker mUserTracker;
+ private final SecureSettings mSecureSettings;
private final DeviceProvisionedController mDeviceProvisionedController;
private final CommandQueue mCommandQueue;
@@ -135,7 +139,9 @@ public class AssistManager {
Lazy<SysUiState> sysUiState,
DefaultUiController defaultUiController,
AssistLogger assistLogger,
- @Main Handler uiHandler) {
+ @Main Handler uiHandler,
+ UserTracker userTracker,
+ SecureSettings secureSettings) {
mContext = context;
mDeviceProvisionedController = controller;
mCommandQueue = commandQueue;
@@ -143,6 +149,8 @@ public class AssistManager {
mAssistDisclosure = new AssistDisclosure(context, uiHandler);
mPhoneStateMonitor = phoneStateMonitor;
mAssistLogger = assistLogger;
+ mUserTracker = userTracker;
+ mSecureSettings = secureSettings;
registerVoiceInteractionSessionListener();
@@ -273,7 +281,7 @@ public class AssistManager {
CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
false /* force */);
- boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ boolean structureEnabled = mSecureSettings.getIntForUser(
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
final SearchManager searchManager =
@@ -300,7 +308,7 @@ public class AssistManager {
@Override
public void run() {
mContext.startActivityAsUser(intent, opts.toBundle(),
- new UserHandle(UserHandle.USER_CURRENT));
+ mUserTracker.getUserHandle());
}
});
} catch (ActivityNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index e4c197ff940e..1404053e4618 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -35,13 +35,13 @@ class AuthBiometricFingerprintAndFaceIconController(
override val actsAsConfirmButton: Boolean = true
- override fun shouldAnimateForTransition(
+ override fun shouldAnimateIconViewForTransition(
@BiometricState oldState: Int,
@BiometricState newState: Int
): Boolean = when (newState) {
STATE_PENDING_CONFIRMATION -> true
STATE_AUTHENTICATED -> false
- else -> super.shouldAnimateForTransition(oldState, newState)
+ else -> super.shouldAnimateIconViewForTransition(oldState, newState)
}
@RawRes
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index b962cc43eddf..436f9dfb0d74 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -104,12 +104,14 @@ open class AuthBiometricFingerprintIconController(
iconView.frame = 0
iconViewOverlay.frame = 0
- if (shouldAnimateForTransition(lastState, newState)) {
+ if (shouldAnimateIconViewForTransition(lastState, newState)) {
iconView.playAnimation()
+ }
+
+ if (shouldAnimateIconViewOverlayForTransition(lastState, newState)) {
iconViewOverlay.playAnimation()
- } else if (lastState == STATE_IDLE && newState == STATE_AUTHENTICATING_ANIMATING_IN) {
- iconView.playAnimation()
}
+
LottieColorUtils.applyDynamicColors(context, iconView)
LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
}
@@ -127,7 +129,7 @@ open class AuthBiometricFingerprintIconController(
}
iconView.frame = 0
- if (shouldAnimateForTransition(lastState, newState)) {
+ if (shouldAnimateIconViewForTransition(lastState, newState)) {
iconView.playAnimation()
}
LottieColorUtils.applyDynamicColors(context, iconView)
@@ -160,7 +162,20 @@ open class AuthBiometricFingerprintIconController(
return if (id != null) context.getString(id) else null
}
- protected open fun shouldAnimateForTransition(
+ protected open fun shouldAnimateIconViewForTransition(
+ @BiometricState oldState: Int,
+ @BiometricState newState: Int
+ ) = when (newState) {
+ STATE_HELP,
+ STATE_ERROR -> true
+ STATE_AUTHENTICATING_ANIMATING_IN,
+ STATE_AUTHENTICATING ->
+ oldState == STATE_ERROR || oldState == STATE_HELP || oldState == STATE_IDLE
+ STATE_AUTHENTICATED -> true
+ else -> false
+ }
+
+ protected open fun shouldAnimateIconViewOverlayForTransition(
@BiometricState oldState: Int,
@BiometricState newState: Int
) = when (newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 1afa9b26ce98..6f594d5eb0e2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -111,7 +111,7 @@ constructor(
context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong()
private val isReverseDefaultRotation =
- context.getResources().getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)
+ context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)
private var overlayHideAnimator: ViewPropertyAnimator? = null
@@ -268,10 +268,12 @@ constructor(
val isDefaultOrientation =
if (isReverseDefaultRotation) !isNaturalOrientation else isNaturalOrientation
val size = windowManager.maximumWindowMetrics.bounds
+
val displayWidth = if (isDefaultOrientation) size.width() else size.height()
val displayHeight = if (isDefaultOrientation) size.height() else size.width()
val boundsWidth = if (isDefaultOrientation) bounds.width() else bounds.height()
val boundsHeight = if (isDefaultOrientation) bounds.height() else bounds.width()
+
val sensorBounds =
if (overlayOffsets.isYAligned()) {
Rect(
@@ -297,6 +299,7 @@ constructor(
overlayViewParams.x = sensorBounds.left
overlayViewParams.y = sensorBounds.top
+
windowManager.updateViewLayout(overlayView, overlayViewParams)
}
@@ -306,7 +309,12 @@ constructor(
}
// hide after a few seconds if the sensor is oriented down and there are
// large overlapping system bars
- val rotation = context.display?.rotation
+ var rotation = context.display?.rotation
+
+ if (rotation != null) {
+ rotation = getRotationFromDefault(rotation)
+ }
+
if (
windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar() &&
((rotation == Surface.ROTATION_270 && overlayOffsets.isYAligned()) ||
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3a9706da9090..3fd00ae8ec81 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -87,6 +87,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
@@ -151,6 +152,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
@NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@Nullable private final TouchProcessor mTouchProcessor;
@NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor;
+ @NonNull private final SecureSettings mSecureSettings;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@@ -240,7 +242,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
mLockscreenShadeTransitionController, mConfigurationController,
mKeyguardStateController,
mUnlockedScreenOffAnimationController,
- mUdfpsDisplayMode, requestId, reason, callback,
+ mUdfpsDisplayMode, mSecureSettings, requestId, reason, callback,
(view, event, fromUdfpsView) -> onTouch(requestId, event,
fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags,
mPrimaryBouncerInteractor, mAlternateBouncerInteractor)));
@@ -723,7 +725,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
@NonNull @BiometricsBackground Executor biometricsExecutor,
@NonNull PrimaryBouncerInteractor primaryBouncerInteractor,
@NonNull SinglePointerTouchProcessor singlePointerTouchProcessor,
- @NonNull AlternateBouncerInteractor alternateBouncerInteractor) {
+ @NonNull AlternateBouncerInteractor alternateBouncerInteractor,
+ @NonNull SecureSettings secureSettings) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -764,6 +767,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
mBiometricExecutor = biometricsExecutor;
mPrimaryBouncerInteractor = primaryBouncerInteractor;
mAlternateBouncerInteractor = alternateBouncerInteractor;
+ mSecureSettings = secureSettings;
mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
? singlePointerTouchProcessor : null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index a3c4985fd5cc..b6b5d26b398c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -60,6 +60,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.settings.SecureSettings
private const val TAG = "UdfpsControllerOverlay"
@@ -89,6 +90,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
private val keyguardStateController: KeyguardStateController,
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
+ private val secureSettings: SecureSettings,
val requestId: Long,
@ShowReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
@@ -131,7 +133,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
/** A helper if the [requestReason] was due to enrollment. */
val enrollHelper: UdfpsEnrollHelper? =
if (requestReason.isEnrollmentReason() && !shouldRemoveEnrollmentUi()) {
- UdfpsEnrollHelper(context, fingerprintManager, requestReason)
+ UdfpsEnrollHelper(context, fingerprintManager, secureSettings, requestReason)
} else {
null
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index d5c763d3b6e2..cfa8ec5dbf1a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -24,11 +24,12 @@ import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.UserHandle;
-import android.provider.Settings;
import android.util.Log;
import android.util.TypedValue;
import android.view.accessibility.AccessibilityManager;
+import com.android.systemui.util.settings.SecureSettings;
+
import java.util.ArrayList;
import java.util.List;
@@ -51,8 +52,8 @@ public class UdfpsEnrollHelper {
void onLastStepAcquired();
}
- @NonNull private final Context mContext;
@NonNull private final FingerprintManager mFingerprintManager;
+ @NonNull private final SecureSettings mSecureSettings;
// IUdfpsOverlayController reason
private final int mEnrollReason;
private final boolean mAccessibilityEnabled;
@@ -70,10 +71,11 @@ public class UdfpsEnrollHelper {
@Nullable Listener mListener;
public UdfpsEnrollHelper(@NonNull Context context,
- @NonNull FingerprintManager fingerprintManager, int reason) {
+ @NonNull FingerprintManager fingerprintManager, SecureSettings secureSettings,
+ int reason) {
- mContext = context;
mFingerprintManager = fingerprintManager;
+ mSecureSettings = secureSettings;
mEnrollReason = reason;
final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
@@ -84,8 +86,7 @@ public class UdfpsEnrollHelper {
// Number of pixels per mm
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
context.getResources().getDisplayMetrics());
- boolean useNewCoords = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- NEW_COORDS_OVERRIDE, 0,
+ boolean useNewCoords = mSecureSettings.getIntForUser(NEW_COORDS_OVERRIDE, 0,
UserHandle.USER_CURRENT) != 0;
if (useNewCoords && (Build.IS_ENG || Build.IS_USERDEBUG)) {
Log.v(TAG, "Using new coordinates");
@@ -210,8 +211,7 @@ public class UdfpsEnrollHelper {
float scale = SCALE;
if (Build.IS_ENG || Build.IS_USERDEBUG) {
- scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
- SCALE_OVERRIDE, SCALE,
+ scale = mSecureSettings.getFloatForUser(SCALE_OVERRIDE, SCALE,
UserHandle.USER_CURRENT);
}
final int index = mLocationsEnrolled - mCenterTouchCount;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index cee228252da9..63a1b76b8103 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -32,6 +32,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -41,7 +42,6 @@ import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.KeyguardViewManagerCallback
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
index 58d40d349dec..4227a7a67330 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
@@ -25,13 +25,13 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.RemoteException
-import android.os.UserHandle
import android.util.Log
import android.view.WindowManager
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -55,6 +55,7 @@ class CameraGestureHelper @Inject constructor(
private val cameraIntents: CameraIntentsWrapper,
private val contentResolver: ContentResolver,
@Main private val uiExecutor: Executor,
+ private val userTracker: UserTracker
) {
/**
* Whether the camera application can be launched for the camera launch gesture.
@@ -111,7 +112,7 @@ class CameraGestureHelper @Inject constructor(
Intent.FLAG_ACTIVITY_NEW_TASK,
null,
activityOptions.toBundle(),
- UserHandle.CURRENT.identifier,
+ userTracker.userId,
)
} catch (e: RemoteException) {
Log.w(
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt
index 867faf9843fe..cc43e7ed25a5 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt
@@ -20,15 +20,13 @@ import android.content.Context
import android.content.Intent
import android.provider.MediaStore
import android.text.TextUtils
-
import com.android.systemui.R
class CameraIntents {
companion object {
- val DEFAULT_SECURE_CAMERA_INTENT_ACTION =
- MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE
- val DEFAULT_INSECURE_CAMERA_INTENT_ACTION =
- MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA
+ val DEFAULT_SECURE_CAMERA_INTENT_ACTION = MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE
+ val DEFAULT_INSECURE_CAMERA_INTENT_ACTION = MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA
+ private val VIDEO_CAMERA_INTENT_ACTION = MediaStore.INTENT_ACTION_VIDEO_CAMERA
const val EXTRA_LAUNCH_SOURCE = "com.android.systemui.camera_launch_source"
@JvmStatic
@@ -44,18 +42,14 @@ class CameraIntents {
@JvmStatic
fun getInsecureCameraIntent(context: Context): Intent {
val intent = Intent(DEFAULT_INSECURE_CAMERA_INTENT_ACTION)
- getOverrideCameraPackage(context)?.let {
- intent.setPackage(it)
- }
+ getOverrideCameraPackage(context)?.let { intent.setPackage(it) }
return intent
}
@JvmStatic
fun getSecureCameraIntent(context: Context): Intent {
val intent = Intent(DEFAULT_SECURE_CAMERA_INTENT_ACTION)
- getOverrideCameraPackage(context)?.let {
- intent.setPackage(it)
- }
+ getOverrideCameraPackage(context)?.let { intent.setPackage(it) }
return intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
}
@@ -68,5 +62,11 @@ class CameraIntents {
fun isInsecureCameraIntent(intent: Intent?): Boolean {
return intent?.getAction()?.equals(DEFAULT_INSECURE_CAMERA_INTENT_ACTION) ?: false
}
+
+ /** Returns an [Intent] that can be used to start the camera in video mode. */
+ @JvmStatic
+ fun getVideoCameraIntent(): Intent {
+ return Intent(VIDEO_CAMERA_INTENT_ACTION)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt
index cf02f8fb4a3c..a434617f2da7 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt
@@ -21,7 +21,9 @@ import android.content.Intent
import javax.inject.Inject
/** Injectable wrapper around [CameraIntents]. */
-class CameraIntentsWrapper @Inject constructor(
+class CameraIntentsWrapper
+@Inject
+constructor(
private val context: Context,
) {
@@ -40,4 +42,9 @@ class CameraIntentsWrapper @Inject constructor(
fun getInsecureCameraIntent(): Intent {
return CameraIntents.getInsecureCameraIntent(context)
}
+
+ /** Returns an [Intent] that can be used to start the camera in video mode. */
+ fun getVideoCameraIntent(): Intent {
+ return CameraIntents.getVideoCameraIntent()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
index 1454210ad798..fb0c0a69e7c8 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
@@ -20,7 +20,7 @@ import android.content.Context
import android.content.res.Configuration
import android.graphics.PixelFormat
import android.os.SystemProperties
-import android.util.DisplayMetrics
+import android.view.Surface
import android.view.View
import android.view.WindowManager
import com.android.internal.annotations.VisibleForTesting
@@ -36,7 +36,6 @@ import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import javax.inject.Inject
@@ -172,30 +171,28 @@ class WiredChargingRippleController @Inject constructor(
}
private fun layoutRipple() {
- val displayMetrics = DisplayMetrics()
- context.display.getRealMetrics(displayMetrics)
- val width = displayMetrics.widthPixels
- val height = displayMetrics.heightPixels
+ val bounds = windowManager.currentWindowMetrics.bounds
+ val width = bounds.width()
+ val height = bounds.height()
val maxDiameter = Integer.max(width, height) * 2f
rippleView.setMaxSize(maxDiameter, maxDiameter)
- when (RotationUtils.getExactRotation(context)) {
- RotationUtils.ROTATION_LANDSCAPE -> {
+ when (context.display.rotation) {
+ Surface.ROTATION_0 -> {
+ rippleView.setCenter(
+ width * normalizedPortPosX, height * normalizedPortPosY)
+ }
+ Surface.ROTATION_90 -> {
rippleView.setCenter(
width * normalizedPortPosY, height * (1 - normalizedPortPosX))
}
- RotationUtils.ROTATION_UPSIDE_DOWN -> {
+ Surface.ROTATION_180 -> {
rippleView.setCenter(
width * (1 - normalizedPortPosX), height * (1 - normalizedPortPosY))
}
- RotationUtils.ROTATION_SEASCAPE -> {
+ Surface.ROTATION_270 -> {
rippleView.setCenter(
width * (1 - normalizedPortPosY), height * normalizedPortPosX)
}
- else -> {
- // ROTATION_NONE
- rippleView.setCenter(
- width * normalizedPortPosX, height * normalizedPortPosY)
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 6d13740afe8b..2d0dfa1d921b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -54,6 +54,7 @@ import com.android.systemui.motiontool.MotionToolModule;
import com.android.systemui.navigationbar.NavigationBarComponent;
import com.android.systemui.notetask.NoteTaskModule;
import com.android.systemui.people.PeopleModule;
+import com.android.systemui.plugins.BcSmartspaceConfigPlugin;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.privacy.PrivacyModule;
import com.android.systemui.qs.FgsManagerController;
@@ -211,6 +212,9 @@ public abstract class SystemUIModule {
abstract BcSmartspaceDataPlugin optionalBcSmartspaceDataPlugin();
@BindsOptionalOf
+ abstract BcSmartspaceConfigPlugin optionalBcSmartspaceConfigPlugin();
+
+ @BindsOptionalOf
abstract Recents optionalRecents();
@BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 2a3d67fd7a8d..c331164f001b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -17,12 +17,12 @@
package com.android.systemui.doze;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.UserHandle;
import android.util.Log;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeMachine.State;
import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.settings.UserTracker;
import java.io.PrintWriter;
@@ -40,14 +40,17 @@ public class DozeDockHandler implements DozeMachine.Part {
private final AmbientDisplayConfiguration mConfig;
private DozeMachine mMachine;
private final DockManager mDockManager;
+ private final UserTracker mUserTracker;
private final DockEventListener mDockEventListener;
private int mDockState = DockManager.STATE_NONE;
@Inject
- DozeDockHandler(AmbientDisplayConfiguration config, DockManager dockManager) {
+ DozeDockHandler(AmbientDisplayConfiguration config, DockManager dockManager,
+ UserTracker userTracker) {
mConfig = config;
mDockManager = dockManager;
+ mUserTracker = userTracker;
mDockEventListener = new DockEventListener();
}
@@ -100,7 +103,7 @@ public class DozeDockHandler implements DozeMachine.Part {
nextState = State.DOZE_AOD_DOCKED;
break;
case DockManager.STATE_NONE:
- nextState = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) ? State.DOZE_AOD
+ nextState = mConfig.alwaysOnEnabled(mUserTracker.getUserId()) ? State.DOZE_AOD
: State.DOZE;
break;
case DockManager.STATE_DOCKED_HIDE:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 96c35d43052e..fc3263fd3d11 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -23,7 +23,6 @@ import android.annotation.MainThread;
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Trace;
-import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
@@ -33,6 +32,7 @@ import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.doze.dagger.WrappedService;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
import com.android.systemui.util.wakelock.WakeLock;
@@ -149,6 +149,7 @@ public class DozeMachine {
private final DozeHost mDozeHost;
private final DockManager mDockManager;
private final Part[] mParts;
+ private final UserTracker mUserTracker;
private final ArrayList<State> mQueuedRequests = new ArrayList<>();
private State mState = State.UNINITIALIZED;
@@ -161,7 +162,7 @@ public class DozeMachine {
AmbientDisplayConfiguration ambientDisplayConfig,
WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
DozeLog dozeLog, DockManager dockManager,
- DozeHost dozeHost, Part[] parts) {
+ DozeHost dozeHost, Part[] parts, UserTracker userTracker) {
mDozeService = service;
mAmbientDisplayConfig = ambientDisplayConfig;
mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -170,6 +171,7 @@ public class DozeMachine {
mDockManager = dockManager;
mDozeHost = dozeHost;
mParts = parts;
+ mUserTracker = userTracker;
for (Part part : parts) {
part.setDozeMachine(this);
}
@@ -429,7 +431,7 @@ public class DozeMachine {
nextState = State.FINISH;
} else if (mDockManager.isDocked()) {
nextState = mDockManager.isHidden() ? State.DOZE : State.DOZE_AOD_DOCKED;
- } else if (mAmbientDisplayConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
+ } else if (mAmbientDisplayConfig.alwaysOnEnabled(mUserTracker.getUserId())) {
nextState = State.DOZE_AOD;
} else {
nextState = State.DOZE;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 937884c79072..4cade77c8312 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -43,6 +43,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.util.settings.SystemSettings;
import java.io.PrintWriter;
import java.util.Objects;
@@ -78,6 +79,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private final DozeParameters mDozeParameters;
private final DevicePostureController mDevicePostureController;
private final DozeLog mDozeLog;
+ private final SystemSettings mSystemSettings;
private final int[] mSensorToBrightness;
private final int[] mSensorToScrimOpacity;
private final int mScreenBrightnessDim;
@@ -110,7 +112,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
WakefulnessLifecycle wakefulnessLifecycle,
DozeParameters dozeParameters,
DevicePostureController devicePostureController,
- DozeLog dozeLog) {
+ DozeLog dozeLog,
+ SystemSettings systemSettings) {
mContext = context;
mDozeService = service;
mSensorManager = sensorManager;
@@ -122,6 +125,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
mDozeHost = host;
mHandler = handler;
mDozeLog = dozeLog;
+ mSystemSettings = systemSettings;
mScreenBrightnessMinimumDimAmountFloat = context.getResources().getFloat(
R.dimen.config_screenBrightnessMinimumDimAmountFloat);
@@ -257,7 +261,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
}
//TODO: brightnessfloat change usages to float.
private int clampToUserSetting(int brightness) {
- int userSetting = Settings.System.getIntForUser(mContext.getContentResolver(),
+ int userSetting = mSystemSettings.getIntForUser(
Settings.System.SCREEN_BRIGHTNESS, Integer.MAX_VALUE,
UserHandle.USER_CURRENT);
return Math.min(brightness, userSetting);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 2ef1262fe55e..e3c568a98cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -252,7 +252,7 @@ public class DozeSensors {
new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
mConfig.wakeScreenGestureAvailable()
- && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT),
+ && mConfig.alwaysOnEnabled(mUserTracker.getUserId()),
DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE,
false /* reports touch coordinates */,
false /* touchscreen */
@@ -293,7 +293,7 @@ public class DozeSensors {
private boolean udfpsLongPressConfigured() {
return mUdfpsEnrolled
- && (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) || mScreenOffUdfpsEnabled);
+ && (mConfig.alwaysOnEnabled(mUserTracker.getUserId()) || mScreenOffUdfpsEnabled);
}
private boolean quickPickUpConfigured() {
@@ -694,13 +694,13 @@ public class DozeSensors {
}
protected boolean enabledBySetting() {
- if (!mConfig.enabled(UserHandle.USER_CURRENT)) {
+ if (!mConfig.enabled(mUserTracker.getUserId())) {
return false;
} else if (TextUtils.isEmpty(mSetting)) {
return true;
}
return mSecureSettings.getIntForUser(mSetting, mSettingDefault ? 1 : 0,
- UserHandle.USER_CURRENT) != 0;
+ mUserTracker.getUserId()) != 0;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
index e6d98655b119..de0bdd344a72 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
@@ -20,10 +20,10 @@ import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.PowerManager;
-import android.os.UserHandle;
import android.text.TextUtils;
import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import java.io.PrintWriter;
@@ -57,6 +57,7 @@ public class DozeSuppressor implements DozeMachine.Part {
private final AmbientDisplayConfiguration mConfig;
private final DozeLog mDozeLog;
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
+ private final UserTracker mUserTracker;
private boolean mIsCarModeEnabled = false;
@@ -65,11 +66,13 @@ public class DozeSuppressor implements DozeMachine.Part {
DozeHost dozeHost,
AmbientDisplayConfiguration config,
DozeLog dozeLog,
- Lazy<BiometricUnlockController> biometricUnlockControllerLazy) {
+ Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+ UserTracker userTracker) {
mDozeHost = dozeHost;
mConfig = config;
mDozeLog = dozeLog;
mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
+ mUserTracker = userTracker;
}
@Override
@@ -148,7 +151,7 @@ public class DozeSuppressor implements DozeMachine.Part {
private void handleCarModeExited() {
mDozeLog.traceCarModeEnded();
- mMachine.requestState(mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)
+ mMachine.requestState(mConfig.alwaysOnEnabled(mUserTracker.getUserId())
? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE);
}
@@ -166,7 +169,7 @@ public class DozeSuppressor implements DozeMachine.Part {
if (mDozeHost.isPowerSaveActive()) {
nextState = DozeMachine.State.DOZE;
} else if (mMachine.getState() == DozeMachine.State.DOZE
- && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
+ && mConfig.alwaysOnEnabled(mUserTracker.getUserId())) {
nextState = DozeMachine.State.DOZE_AOD;
}
@@ -181,7 +184,7 @@ public class DozeSuppressor implements DozeMachine.Part {
// handles suppression changes, while DozeMachine#transitionPolicy handles gating
// transitions to DOZE_AOD
final DozeMachine.State nextState;
- if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) {
+ if (mConfig.alwaysOnEnabled(mUserTracker.getUserId()) && !suppressed) {
nextState = DozeMachine.State.DOZE_AOD;
} else {
nextState = DozeMachine.State.DOZE;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 3106173d81b2..33c8379d2e5c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -38,6 +38,7 @@ import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -85,8 +86,9 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
private boolean mBouncerAnimating;
- private final KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback =
- new KeyguardBouncer.PrimaryBouncerExpansionCallback() {
+ private final PrimaryBouncerExpansionCallback
+ mBouncerExpansionCallback =
+ new PrimaryBouncerExpansionCallback() {
@Override
public void onStartingToShow() {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index a9a9caed314b..dd01be0ef031 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -208,6 +208,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
});
}
+ @Override
+ public void onEndDream() {
+ mExecutor.execute(() -> {
+ resetCurrentDreamOverlayLocked();
+ });
+ }
+
private Lifecycle.State getCurrentStateLocked() {
return mLifecycleRegistry.getCurrentState();
}
@@ -291,6 +298,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mDreamOverlayContainerViewController = null;
mDreamOverlayTouchMonitor = null;
+ mWindow = null;
mStarted = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index f1bb156199ef..90c440c403ec 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -25,7 +25,6 @@ import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
-import android.os.UserHandle;
import android.provider.Settings;
import android.text.format.DateFormat;
import android.util.PluralsMessageFormatter;
@@ -37,6 +36,7 @@ import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -72,6 +72,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mDreamOverlayNotificationCountProvider;
private final ZenModeController mZenModeController;
private final DreamOverlayStateController mDreamOverlayStateController;
+ private final UserTracker mUserTracker;
private final StatusBarWindowStateController mStatusBarWindowStateController;
private final DreamOverlayStatusBarItemsProvider mStatusBarItemsProvider;
private final Executor mMainExecutor;
@@ -154,7 +155,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
ZenModeController zenModeController,
StatusBarWindowStateController statusBarWindowStateController,
DreamOverlayStatusBarItemsProvider statusBarItemsProvider,
- DreamOverlayStateController dreamOverlayStateController) {
+ DreamOverlayStateController dreamOverlayStateController,
+ UserTracker userTracker) {
super(view);
mResources = resources;
mMainExecutor = mainExecutor;
@@ -169,6 +171,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mStatusBarItemsProvider = statusBarItemsProvider;
mZenModeController = zenModeController;
mDreamOverlayStateController = dreamOverlayStateController;
+ mUserTracker = userTracker;
// Register to receive show/hide updates for the system status bar. Our custom status bar
// needs to hide when the system status bar is showing to ovoid overlapping status bars.
@@ -259,7 +262,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
private void updateAlarmStatusIcon() {
final AlarmManager.AlarmClockInfo alarm =
- mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
+ mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
showIcon(
DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 53f8f196f787..9a28ab9f7811 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -64,6 +64,10 @@ object Flags {
// TODO(b/259130119): Tracking Bug
val FSI_ON_DND_UPDATE = unreleasedFlag(259130119, "fsi_on_dnd_update", teamfood = true)
+ // TODO(b/265804648): Tracking Bug
+ @JvmField
+ val DISABLE_FSI = unreleasedFlag(265804648, "disable_fsi")
+
// TODO(b/254512538): Tracking Bug
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply", teamfood = true)
@@ -77,12 +81,6 @@ object Flags {
// TODO(b/254512731): Tracking Bug
@JvmField val NOTIFICATION_DISMISSAL_FADE = releasedFlag(113, "notification_dismissal_fade")
- // TODO(b/259558771): Tracking Bug
- val STABILITY_INDEX_FIX = releasedFlag(114, "stability_index_fix")
-
- // TODO(b/259559750): Tracking Bug
- val SEMI_STABLE_SORT = releasedFlag(115, "semi_stable_sort")
-
@JvmField val USE_ROUNDNESS_SOURCETYPES = releasedFlag(116, "use_roundness_sourcetype")
// TODO(b/259217907)
@@ -108,6 +106,10 @@ object Flags {
val FILTER_UNSEEN_NOTIFS_ON_KEYGUARD =
unreleasedFlag(254647461, "filter_unseen_notifs_on_keyguard", teamfood = true)
+ // TODO(b/263414400): Tracking Bug
+ @JvmField
+ val NOTIFICATION_ANIMATE_BIG_PICTURE = unreleasedFlag(120, "notification_animate_big_picture")
+
// 200 - keyguard/lockscreen
// ** Flag retired **
// public static final BooleanFlag KEYGUARD_LAYOUT =
@@ -181,7 +183,7 @@ object Flags {
* of the Alternate/Authentication Bouncer. No visual UI changes.
*/
// TODO(b/260619425): Tracking Bug
- @JvmField val MODERN_ALTERNATE_BOUNCER = unreleasedFlag(219, "modern_alternate_bouncer")
+ @JvmField val MODERN_ALTERNATE_BOUNCER = releasedFlag(219, "modern_alternate_bouncer")
/** Flag to control the migration of face auth to modern architecture. */
// TODO(b/262838215): Tracking bug
@@ -214,6 +216,11 @@ object Flags {
val ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS =
unreleasedFlag(226, "enable_wallet_contextual_loyalty_cards", teamfood = false)
+ // TODO(b/242908637): Tracking Bug
+ @JvmField
+ val WALLPAPER_FULLSCREEN_PREVIEW =
+ unreleasedFlag(227, "wallpaper_fullscreen_preview", teamfood = true)
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -227,7 +234,8 @@ object Flags {
// TODO(b/258517050): Clean up after the feature is launched.
@JvmField
- val SMARTSPACE_DATE_WEATHER_DECOUPLED = unreleasedFlag(403, "smartspace_date_weather_decoupled")
+ val SMARTSPACE_DATE_WEATHER_DECOUPLED =
+ sysPropBooleanFlag(403, "persist.sysui.ss.dw_decoupled", default = false)
// 500 - quick settings
@@ -343,6 +351,10 @@ object Flags {
// TODO(b/263512203): Tracking Bug
val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator", teamfood = true)
+ // TODO(b/265813373): Tracking Bug
+ val MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE =
+ unreleasedFlag(912, "media_ttt_dismiss_gesture", teamfood = true)
+
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
@@ -458,6 +470,16 @@ object Flags {
val WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM =
unreleasedFlag(1206, "persist.wm.debug.predictive_back_bouncer_anim", teamfood = true)
+ // TODO(b/238475428): Tracking Bug
+ @JvmField
+ val WM_SHADE_ALLOW_BACK_GESTURE =
+ unreleasedFlag(1207, "persist.wm.debug.shade_allow_back_gesture", teamfood = false)
+
+ // TODO(b/238475428): Tracking Bug
+ @JvmField
+ val WM_SHADE_ANIMATE_BACK_GESTURE =
+ unreleasedFlag(1208, "persist.wm.debug.shade_animate_back_gesture", teamfood = true)
+
// 1300 - screenshots
// TODO(b/254513155): Tracking Bug
@JvmField
@@ -487,8 +509,7 @@ object Flags {
// 1800 - shade container
@JvmField
- val LEAVE_SHADE_OPEN_FOR_BUGREPORT =
- unreleasedFlag(1800, "leave_shade_open_for_bugreport", teamfood = true)
+ val LEAVE_SHADE_OPEN_FOR_BUGREPORT = releasedFlag(1800, "leave_shade_open_for_bugreport")
// 1900
@JvmField val NOTE_TASKS = unreleasedFlag(1900, "keycode_flag")
@@ -537,6 +558,18 @@ object Flags {
val OUTPUT_SWITCHER_SHOW_API_ENABLED =
unreleasedFlag(2503, "output_switcher_show_api_enabled", teamfood = true)
+ // 2700 - unfold transitions
+ // TODO(b/265764985): Tracking Bug
+ @Keep
+ @JvmField
+ val ENABLE_DARK_VIGNETTE_WHEN_FOLDING =
+ unreleasedFlag(2700, "enable_dark_vignette_when_folding")
+
// TODO(b259590361): Tracking bug
val EXPERIMENTAL_FLAG = unreleasedFlag(2, "exp_flag_release")
+
+ // 2600 - keyboard shortcut
+ // TODO(b/259352579): Tracking Bug
+ @JvmField
+ val SHORTCUT_LIST_SEARCH_LAYOUT = unreleasedFlag(2600, "shortcut_list_search_layout")
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index db2cd91374e5..e80e71c7b599 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -21,7 +21,6 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
-import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
@@ -901,7 +900,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ mContext.startActivityAsUser(intent, mUserTracker.getUserHandle());
}
}
}
@@ -959,8 +958,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN,
- SCREENSHOT_GLOBAL_ACTIONS, mHandler, null);
+ mScreenshotHelper.takeScreenshot(SCREENSHOT_GLOBAL_ACTIONS, mHandler, null);
mMetricsLogger.action(MetricsEvent.ACTION_SCREENSHOT_POWER_MENU);
mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_PRESS);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 4f1a2b34f07c..ad7973ed0b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -24,7 +24,6 @@ import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.hardware.input.InputManager;
@@ -53,6 +52,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.CoreStartable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -108,6 +108,7 @@ public class KeyboardUI implements CoreStartable, InputManager.OnTabletModeChang
protected volatile Context mContext;
private final Provider<LocalBluetoothManager> mBluetoothManagerProvider;
+ private final SecureSettings mSecureSettings;
private boolean mEnabled;
private String mKeyboardName;
@@ -125,9 +126,11 @@ public class KeyboardUI implements CoreStartable, InputManager.OnTabletModeChang
private int mState;
@Inject
- public KeyboardUI(Context context, Provider<LocalBluetoothManager> bluetoothManagerProvider) {
+ public KeyboardUI(Context context, Provider<LocalBluetoothManager> bluetoothManagerProvider,
+ SecureSettings secureSettings) {
mContext = context;
this.mBluetoothManagerProvider = bluetoothManagerProvider;
+ mSecureSettings = secureSettings;
}
@Override
@@ -298,9 +301,8 @@ public class KeyboardUI implements CoreStartable, InputManager.OnTabletModeChang
}
private boolean isUserSetupComplete() {
- ContentResolver resolver = mContext.getContentResolver();
- return Secure.getIntForUser(
- resolver, Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ return mSecureSettings.getIntForUser(
+ Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
}
private CachedBluetoothDevice getPairedKeyboard() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index fe84ac5a32bc..95bba131d8de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1334,7 +1334,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mHideAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.lock_screen_behind_enter);
- mWorkLockController = new WorkLockActivityController(mContext);
+ mWorkLockController = new WorkLockActivityController(mContext, mUserTracker);
}
@Override
@@ -1912,12 +1912,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
* Enable the keyguard if the settings are appropriate.
*/
private void doKeyguardLocked(Bundle options) {
- if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {
- // Don't show keyguard during half-booted cryptkeeper stage.
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper");
- return;
- }
-
// if another app is disabling us, don't show
if (!mExternallyEnabled) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
@@ -2287,6 +2281,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
handleKeyguardDone();
+ } else if (mSurfaceBehindRemoteAnimationRunning) {
+ // We're already running the keyguard exit animation, likely due to an in-progress swipe
+ // to unlock.
+ exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false /* cancelled */);
} else if (!mHideAnimationRun) {
if (DEBUG) Log.d(TAG, "tryKeyguardDone: starting pre-hide animation");
mHideAnimationRun = true;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 16817ed4c5fe..b92499eb883e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -26,10 +26,10 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -37,16 +37,20 @@ public class WorkLockActivityController {
private static final String TAG = WorkLockActivityController.class.getSimpleName();
private final Context mContext;
+ private final UserTracker mUserTracker;
private final IActivityTaskManager mIatm;
- public WorkLockActivityController(Context context) {
- this(context, TaskStackChangeListeners.getInstance(), ActivityTaskManager.getService());
+ public WorkLockActivityController(Context context, UserTracker userTracker) {
+ this(context, userTracker, TaskStackChangeListeners.getInstance(),
+ ActivityTaskManager.getService());
}
@VisibleForTesting
WorkLockActivityController(
- Context context, TaskStackChangeListeners tscl, IActivityTaskManager iAtm) {
+ Context context, UserTracker userTracker, TaskStackChangeListeners tscl,
+ IActivityTaskManager iAtm) {
mContext = context;
+ mUserTracker = userTracker;
mIatm = iAtm;
tscl.registerTaskStackListener(mLockListener);
@@ -65,7 +69,8 @@ public class WorkLockActivityController {
options.setLaunchTaskId(info.taskId);
options.setTaskOverlay(true, false /* canResume */);
- final int result = startActivityAsUser(intent, options.toBundle(), UserHandle.USER_CURRENT);
+ final int result = startActivityAsUser(intent, options.toBundle(),
+ mUserTracker.getUserId());
if (ActivityManager.isStartResultSuccessful(result)) {
// OK
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
index 80c6130955c5..faeb48526ae4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data
import android.view.KeyEvent
+import android.window.OnBackAnimationCallback
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter
import java.lang.ref.WeakReference
@@ -51,4 +52,6 @@ interface BouncerViewDelegate {
cancelAction: Runnable?,
)
fun willDismissWithActions(): Boolean
+ /** @return the {@link OnBackAnimationCallback} to animate Bouncer during a back gesture. */
+ fun getBackCallback(): OnBackAnimationCallback
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
index ea5b4f43cc75..76c2430e37ad 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
@@ -25,10 +25,12 @@ package com.android.systemui.keyguard.data.quickaffordance
object BuiltInKeyguardQuickAffordanceKeys {
// Please keep alphabetical order of const names to simplify future maintenance.
const val CAMERA = "camera"
+ const val CREATE_NOTE = "create_note"
const val DO_NOT_DISTURB = "do_not_disturb"
const val FLASHLIGHT = "flashlight"
const val HOME_CONTROLS = "home"
const val QR_CODE_SCANNER = "qr_code_scanner"
const val QUICK_ACCESS_WALLET = "wallet"
+ const val VIDEO_CAMERA = "video_camera"
// Please keep alphabetical order of const names to simplify future maintenance.
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index dbc376e62950..f6e6d6b7dc1b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -26,6 +26,7 @@ import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.StatusBarState
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -46,7 +47,7 @@ constructor(
get() = context.getString(R.string.accessibility_camera_button)
override val pickerIconResourceId: Int
- get() = com.android.internal.R.drawable.perm_group_camera
+ get() = R.drawable.ic_camera
override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState>
get() =
@@ -54,12 +55,20 @@ constructor(
KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon =
Icon.Resource(
- com.android.internal.R.drawable.perm_group_camera,
+ R.drawable.ic_camera,
ContentDescription.Resource(R.string.accessibility_camera_button)
)
)
)
+ override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
+ return if (isLaunchable()) {
+ super.getPickerScreenState()
+ } else {
+ KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
+ }
+ }
+
override fun onTriggered(
expandable: Expandable?
): KeyguardQuickAffordanceConfig.OnTriggeredResult {
@@ -68,4 +77,8 @@ constructor(
.launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE)
return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
}
+
+ private fun isLaunchable(): Boolean {
+ return cameraGestureHelper.get().canCameraGestureBeLaunched(StatusBarState.KEYGUARD)
+ }
}
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 ed1ff329004a..be73f851fa82 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
@@ -128,7 +128,7 @@ constructor(
awaitClose { controller.removeCallback(callback) }
},
secureSettings
- .observerFlow(Settings.Secure.ZEN_DURATION)
+ .observerFlow(userTracker.userId, Settings.Secure.ZEN_DURATION)
.onStart { emit(Unit) }
.map { secureSettings.getInt(Settings.Secure.ZEN_DURATION, ZEN_MODE_OFF) }
.flowOn(backgroundDispatcher)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
index 71d01ebc8496..a1cce5c670ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
@@ -39,6 +39,7 @@ interface KeyguardDataQuickAffordanceModule {
quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
qrCodeScanner: QrCodeScannerKeyguardQuickAffordanceConfig,
camera: CameraQuickAffordanceConfig,
+ videoCamera: VideoCameraQuickAffordanceConfig,
): Set<KeyguardQuickAffordanceConfig> {
return setOf(
camera,
@@ -47,6 +48,7 @@ interface KeyguardDataQuickAffordanceModule {
home,
quickAccessWallet,
qrCodeScanner,
+ videoCamera,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 680c06bf2c64..4ba2eb913742 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -100,9 +100,9 @@ constructor(
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return when {
- !walletController.isWalletEnabled ->
+ !walletController.walletClient.isWalletServiceAvailable ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
- walletController.walletClient.tileIcon == null || queryCards().isEmpty() -> {
+ !walletController.isWalletEnabled || queryCards().isEmpty() -> {
val componentName =
walletController.walletClient.createWalletSettingsIntent().toComponentName()
val actionText =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
new file mode 100644
index 000000000000..d9ec3b1c2f87
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.quickaffordance
+
+import android.app.StatusBarManager
+import android.content.Context
+import android.content.Intent
+import com.android.systemui.ActivityIntentHelper
+import com.android.systemui.R
+import com.android.systemui.animation.Expandable
+import com.android.systemui.camera.CameraIntents
+import com.android.systemui.camera.CameraIntentsWrapper
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.settings.UserTracker
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+@SysUISingleton
+class VideoCameraQuickAffordanceConfig
+@Inject
+constructor(
+ @Application private val context: Context,
+ private val cameraIntents: CameraIntentsWrapper,
+ private val activityIntentHelper: ActivityIntentHelper,
+ private val userTracker: UserTracker,
+) : KeyguardQuickAffordanceConfig {
+
+ private val intent: Intent by lazy {
+ cameraIntents.getVideoCameraIntent().apply {
+ putExtra(
+ CameraIntents.EXTRA_LAUNCH_SOURCE,
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE,
+ )
+ }
+ }
+
+ override val key: String
+ get() = BuiltInKeyguardQuickAffordanceKeys.VIDEO_CAMERA
+
+ override val pickerName: String
+ get() = context.getString(R.string.video_camera)
+
+ override val pickerIconResourceId: Int
+ get() = R.drawable.ic_videocam
+
+ override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState>
+ get() =
+ flowOf(
+ if (isLaunchable()) {
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+ icon =
+ Icon.Resource(
+ R.drawable.ic_videocam,
+ ContentDescription.Resource(R.string.video_camera)
+ )
+ )
+ } else {
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
+ }
+ )
+
+ override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
+ return if (isLaunchable()) {
+ super.getPickerScreenState()
+ } else {
+ KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
+ }
+ }
+
+ override fun onTriggered(
+ expandable: Expandable?
+ ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
+ return KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity(
+ intent = intent,
+ canShowWhileLocked = false,
+ )
+ }
+
+ private fun isLaunchable(): Boolean {
+ return activityIntentHelper.getTargetActivityInfo(
+ intent,
+ userTracker.userId,
+ true,
+ ) != null
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
new file mode 100644
index 000000000000..08edbc6d0163
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -0,0 +1,74 @@
+/*
+ * 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 android.hardware.biometrics.BiometricSourceType
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Encapsulates state about device entry fingerprint auth mechanism. */
+interface DeviceEntryFingerprintAuthRepository {
+ /** Whether the device entry fingerprint auth is locked out. */
+ val isLockedOut: Flow<Boolean>
+}
+
+/**
+ * Implementation of [DeviceEntryFingerprintAuthRepository] that uses [KeyguardUpdateMonitor] as the
+ * source of truth.
+ *
+ * Dependency on [KeyguardUpdateMonitor] will be removed once fingerprint auth state is moved out of
+ * [KeyguardUpdateMonitor]
+ */
+@SysUISingleton
+class DeviceEntryFingerprintAuthRepositoryImpl
+@Inject
+constructor(
+ val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+) : DeviceEntryFingerprintAuthRepository {
+
+ override val isLockedOut: Flow<Boolean> = conflatedCallbackFlow {
+ val sendLockoutUpdate =
+ fun() {
+ trySendWithFailureLogging(
+ keyguardUpdateMonitor.isFingerprintLockedOut,
+ TAG,
+ "onLockedOutStateChanged"
+ )
+ }
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType?) {
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+ sendLockoutUpdate()
+ }
+ }
+ }
+ keyguardUpdateMonitor.registerCallback(callback)
+ sendLockoutUpdate()
+ awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
+ }
+
+ companion object {
+ const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
new file mode 100644
index 000000000000..d90f328719bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
@@ -0,0 +1,99 @@
+/*
+ * 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 android.app.trust.TrustManager
+import com.android.keyguard.logging.TrustRepositoryLogger
+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.dagger.qualifiers.Application
+import com.android.systemui.keyguard.shared.model.TrustModel
+import com.android.systemui.user.data.repository.UserRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
+
+/** Encapsulates any state relevant to trust agents and trust grants. */
+interface TrustRepository {
+ /** Flow representing whether the current user is trusted. */
+ val isCurrentUserTrusted: Flow<Boolean>
+}
+
+@SysUISingleton
+class TrustRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val userRepository: UserRepository,
+ private val trustManager: TrustManager,
+ private val logger: TrustRepositoryLogger,
+) : TrustRepository {
+ private val latestTrustModelForUser = mutableMapOf<Int, TrustModel>()
+
+ private val trust =
+ conflatedCallbackFlow {
+ val callback =
+ object : TrustManager.TrustListener {
+ override fun onTrustChanged(
+ enabled: Boolean,
+ newlyUnlocked: Boolean,
+ userId: Int,
+ flags: Int,
+ grantMsgs: List<String>?
+ ) {
+ logger.onTrustChanged(enabled, newlyUnlocked, userId, flags, grantMsgs)
+ trySendWithFailureLogging(
+ TrustModel(enabled, userId),
+ TrustRepositoryLogger.TAG,
+ "onTrustChanged"
+ )
+ }
+
+ override fun onTrustError(message: CharSequence?) = Unit
+
+ override fun onTrustManagedChanged(enabled: Boolean, userId: Int) = Unit
+ }
+ trustManager.registerTrustListener(callback)
+ logger.trustListenerRegistered()
+ awaitClose {
+ logger.trustListenerUnregistered()
+ trustManager.unregisterTrustListener(callback)
+ }
+ }
+ .onEach {
+ latestTrustModelForUser[it.userId] = it
+ logger.trustModelEmitted(it)
+ }
+ .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
+
+ override val isCurrentUserTrusted: Flow<Boolean>
+ get() =
+ combine(trust, userRepository.selectedUserInfo, ::Pair)
+ .map { latestTrustModelForUser[it.second.id]?.isTrusted ?: false }
+ .distinctUntilChanged()
+ .onEach { logger.isCurrentUserTrusted(it) }
+ .onStart { emit(false) }
+}
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 7134ec0d64f0..81a58286aab7 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
@@ -31,8 +31,10 @@ import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@SysUISingleton
@@ -87,6 +89,9 @@ constructor(
private fun listenForDreamingToOccluded() {
scope.launch {
keyguardInteractor.isDreaming
+ // Add a slight delay, as dreaming and occluded events will arrive with a small gap
+ // in time. This prevents a transition to OCCLUSION happening prematurely.
+ .onEach { delay(50) }
.sample(
combine(
keyguardInteractor.isKeyguardOccluded,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 9203a9b924a7..14f918d78bc6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -50,10 +50,9 @@ constructor(
private fun listenForGoneToDreaming() {
scope.launch {
keyguardInteractor.isAbleToDream
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
- .collect { pair ->
- val (isAbleToDream, keyguardState) = pair
- if (isAbleToDream && keyguardState == KeyguardState.GONE) {
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isAbleToDream, lastStartedStep) ->
+ if (isAbleToDream && lastStartedStep.to == KeyguardState.GONE) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
@@ -72,15 +71,15 @@ constructor(
keyguardInteractor.wakefulnessModel
.sample(
combine(
- keyguardTransitionInteractor.finishedKeyguardState,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
::toTriple
)
- .collect { (wakefulnessState, keyguardState, isAodAvailable) ->
+ .collect { (wakefulnessState, lastStartedStep, isAodAvailable) ->
if (
- keyguardState == KeyguardState.GONE &&
+ lastStartedStep.to == KeyguardState.GONE &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
keyguardTransitionRepository.startTransition(
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 c219380ad263..9ddc575307b5 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
@@ -363,6 +363,10 @@ constructor(
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED,
value = featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS),
),
+ KeyguardPickerFlag(
+ name = Contract.FlagsTable.FLAG_NAME_WALLPAPER_FULLSCREEN_PREVIEW,
+ value = featureFlags.isEnabled(Flags.WALLPAPER_FULLSCREEN_PREVIEW),
+ ),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
index c5e49c61e581..3099a497bf45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
@@ -18,27 +18,29 @@ package com.android.systemui.keyguard.domain.interactor
import android.view.View
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.phone.KeyguardBouncer
+import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
+import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.util.ListenerSet
import javax.inject.Inject
/** Interactor to add and remove callbacks for the bouncer. */
@SysUISingleton
class PrimaryBouncerCallbackInteractor @Inject constructor() {
- private var resetCallbacks = ListenerSet<KeyguardBouncer.KeyguardResetCallback>()
- private var expansionCallbacks = ArrayList<KeyguardBouncer.PrimaryBouncerExpansionCallback>()
+ private var resetCallbacks = ListenerSet<KeyguardResetCallback>()
+ private var expansionCallbacks = ArrayList<PrimaryBouncerExpansionCallback>()
+
/** Add a KeyguardResetCallback. */
- fun addKeyguardResetCallback(callback: KeyguardBouncer.KeyguardResetCallback) {
+ fun addKeyguardResetCallback(callback: KeyguardResetCallback) {
resetCallbacks.addIfAbsent(callback)
}
/** Remove a KeyguardResetCallback. */
- fun removeKeyguardResetCallback(callback: KeyguardBouncer.KeyguardResetCallback) {
+ fun removeKeyguardResetCallback(callback: KeyguardResetCallback) {
resetCallbacks.remove(callback)
}
/** Adds a callback to listen to bouncer expansion updates. */
- fun addBouncerExpansionCallback(callback: KeyguardBouncer.PrimaryBouncerExpansionCallback) {
+ fun addBouncerExpansionCallback(callback: PrimaryBouncerExpansionCallback) {
if (!expansionCallbacks.contains(callback)) {
expansionCallbacks.add(callback)
}
@@ -48,7 +50,7 @@ class PrimaryBouncerCallbackInteractor @Inject constructor() {
* Removes a previously added callback. If the callback was never added, this method does
* nothing.
*/
- fun removeBouncerExpansionCallback(callback: KeyguardBouncer.PrimaryBouncerExpansionCallback) {
+ fun removeBouncerExpansionCallback(callback: PrimaryBouncerExpansionCallback) {
expansionCallbacks.remove(callback)
}
@@ -99,4 +101,40 @@ class PrimaryBouncerCallbackInteractor @Inject constructor() {
callback.onKeyguardReset()
}
}
+
+ /** Callback updated when the primary bouncer's show and hide states change. */
+ interface PrimaryBouncerExpansionCallback {
+ /**
+ * Invoked when the bouncer expansion reaches [EXPANSION_VISIBLE]. This is NOT called each
+ * time the bouncer is shown, but rather only when the fully shown amount has changed based
+ * on the panel expansion. The bouncer's visibility can still change when the expansion
+ * amount hasn't changed. See [PrimaryBouncerInteractor.isFullyShowing] for the checks for
+ * the bouncer showing state.
+ */
+ fun onFullyShown() {}
+
+ /** Invoked when the bouncer is starting to transition to a hidden state. */
+ fun onStartingToHide() {}
+
+ /** Invoked when the bouncer is starting to transition to a visible state. */
+ fun onStartingToShow() {}
+
+ /** Invoked when the bouncer expansion reaches [EXPANSION_HIDDEN]. */
+ fun onFullyHidden() {}
+
+ /**
+ * From 0f [EXPANSION_VISIBLE] when fully visible to 1f [EXPANSION_HIDDEN] when fully hidden
+ */
+ fun onExpansionChanged(bouncerHideAmount: Float) {}
+
+ /**
+ * Invoked when visibility of KeyguardBouncer has changed. Note the bouncer expansion can be
+ * [EXPANSION_VISIBLE], but the view's visibility can be [View.INVISIBLE].
+ */
+ fun onVisibilityChanged(isVisible: Boolean) {}
+ }
+
+ interface KeyguardResetCallback {
+ fun onKeyguardReset()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.kt
new file mode 100644
index 000000000000..4fd14b1ce087
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.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.keyguard.shared.model
+
+/** Represents the trust state */
+data class TrustModel(
+ /** If true, the system believes the environment to be trusted. */
+ val isTrusted: Boolean,
+ /** The user, for which the trust changed. */
+ val userId: Int,
+)
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 9d8bf7deb03e..d020529d2bae 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,14 +342,12 @@ object KeyguardBottomAreaViewBinder {
private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong()
private var longPressAnimator: ViewPropertyAnimator? = null
- private var downTimestamp = 0L
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
return when (event?.actionMasked) {
MotionEvent.ACTION_DOWN ->
if (viewModel.configKey != null) {
- downTimestamp = System.currentTimeMillis()
longPressAnimator =
view
.animate()
@@ -396,7 +394,7 @@ object KeyguardBottomAreaViewBinder {
MotionEvent.ACTION_UP -> {
cancel(
onAnimationEnd =
- if (System.currentTimeMillis() - downTimestamp < longPressDurationMs) {
+ if (event.eventTime - event.downTime < longPressDurationMs) {
Runnable {
messageDisplayer.invoke(
R.string.keyguard_affordance_press_too_short
@@ -437,7 +435,6 @@ object KeyguardBottomAreaViewBinder {
}
private fun cancel(onAnimationEnd: Runnable? = null) {
- downTimestamp = 0L
longPressAnimator?.cancel()
longPressAnimator = null
view.animate().scaleX(1f).scaleY(1f).withEndAction(onAnimationEnd)
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 49d3748dcf3d..5e46c5d1f67a 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
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.binder
import android.view.KeyEvent
import android.view.View
import android.view.ViewGroup
+import android.window.OnBackAnimationCallback
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.internal.policy.SystemBarUtils
@@ -55,6 +56,10 @@ object KeyguardBouncerViewBinder {
mode == KeyguardSecurityModel.SecurityMode.SimPuk
}
+ override fun getBackCallback(): OnBackAnimationCallback {
+ return hostViewController.backCallback
+ }
+
override fun shouldDismissOnMenuPressed(): Boolean {
return hostViewController.shouldEnableMenuKey()
}
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 d7817e1dc4f0..15306f9cc23e 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -191,15 +191,12 @@ public class LogModule {
false /* systrace */);
}
- /**
- * Provides a logging buffer for logs related to swiping away the status bar while in immersive
- * mode. See {@link com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureLogger}.
- */
+ /** Provides a logging buffer for logs related to swipe up gestures. */
@Provides
@SysUISingleton
- @SwipeStatusBarAwayLog
- public static LogBuffer provideSwipeAwayGestureLogBuffer(LogBufferFactory factory) {
- return factory.create("SwipeStatusBarAwayLog", 30);
+ @SwipeUpLog
+ public static LogBuffer provideSwipeUpLogBuffer(LogBufferFactory factory) {
+ return factory.create("SwipeUpLog", 30);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
index 4c276e2bfaab..d58b538f2047 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SwipeUpLog.java
@@ -27,10 +27,10 @@ import javax.inject.Qualifier;
/**
* A {@link LogBuffer} for
- * {@link com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureLogger}.
+ * {@link com.android.systemui.statusbar.gesture.SwipeUpGestureLogger}.
*/
@Qualifier
@Documented
@Retention(RUNTIME)
-public @interface SwipeStatusBarAwayLog {
+public @interface SwipeUpLog {
}
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 93be6a78ccd5..4827a16d229d 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
@@ -162,8 +162,8 @@ internal constructor(
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
UI_MODE_NIGHT_YES
)
- colorScheme.accent1[2]
- else colorScheme.accent1[3]
+ colorScheme.accent1.s100
+ else colorScheme.accent1.s200
},
{ seamlessColor: Int ->
val accentColorList = ColorStateList.valueOf(seamlessColor)
@@ -230,7 +230,14 @@ internal constructor(
fun updateColorScheme(colorScheme: ColorScheme?): Boolean {
var anyChanged = false
- colorTransitions.forEach { anyChanged = it.updateColorScheme(colorScheme) || anyChanged }
+ colorTransitions.forEach {
+ val isChanged = it.updateColorScheme(colorScheme)
+
+ // Ignore changes to colorSeamless, since that is expected when toggling dark mode
+ if (it == colorSeamless) return@forEach
+
+ anyChanged = isChanged || anyChanged
+ }
colorScheme?.let { mediaViewHolder.gutsViewHolder.colorScheme = colorScheme }
return anyChanged
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaColorSchemes.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaColorSchemes.kt
index 82abf9bfcc80..2a8362b64cd6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaColorSchemes.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaColorSchemes.kt
@@ -19,28 +19,28 @@ package com.android.systemui.media.controls.ui
import com.android.systemui.monet.ColorScheme
/** Returns the surface color for media controls based on the scheme. */
-internal fun surfaceFromScheme(scheme: ColorScheme) = scheme.accent2[9] // A2-800
+internal fun surfaceFromScheme(scheme: ColorScheme) = scheme.accent2.s800 // A2-800
/** Returns the primary accent color for media controls based on the scheme. */
-internal fun accentPrimaryFromScheme(scheme: ColorScheme) = scheme.accent1[2] // A1-100
+internal fun accentPrimaryFromScheme(scheme: ColorScheme) = scheme.accent1.s100 // A1-100
/** Returns the secondary accent color for media controls based on the scheme. */
-internal fun accentSecondaryFromScheme(scheme: ColorScheme) = scheme.accent1[3] // A1-200
+internal fun accentSecondaryFromScheme(scheme: ColorScheme) = scheme.accent1.s200 // A1-200
/** Returns the primary text color for media controls based on the scheme. */
-internal fun textPrimaryFromScheme(scheme: ColorScheme) = scheme.neutral1[1] // N1-50
+internal fun textPrimaryFromScheme(scheme: ColorScheme) = scheme.neutral1.s50 // N1-50
/** Returns the inverse of the primary text color for media controls based on the scheme. */
-internal fun textPrimaryInverseFromScheme(scheme: ColorScheme) = scheme.neutral1[10] // N1-900
+internal fun textPrimaryInverseFromScheme(scheme: ColorScheme) = scheme.neutral1.s900 // N1-900
/** Returns the secondary text color for media controls based on the scheme. */
-internal fun textSecondaryFromScheme(scheme: ColorScheme) = scheme.neutral2[3] // N2-200
+internal fun textSecondaryFromScheme(scheme: ColorScheme) = scheme.neutral2.s200 // N2-200
/** Returns the tertiary text color for media controls based on the scheme. */
-internal fun textTertiaryFromScheme(scheme: ColorScheme) = scheme.neutral2[5] // N2-400
+internal fun textTertiaryFromScheme(scheme: ColorScheme) = scheme.neutral2.s400 // N2-400
/** Returns the color for the start of the background gradient based on the scheme. */
-internal fun backgroundStartFromScheme(scheme: ColorScheme) = scheme.accent2[8] // A2-700
+internal fun backgroundStartFromScheme(scheme: ColorScheme) = scheme.accent2.s700 // A2-700
/** Returns the color for the end of the background gradient based on the scheme. */
-internal fun backgroundEndFromScheme(scheme: ColorScheme) = scheme.accent1[8] // A1-700
+internal fun backgroundEndFromScheme(scheme: ColorScheme) = scheme.accent1.s700 // A1-700
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index a9e1a4d325d2..4803371e97c1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -95,6 +95,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
private RecyclerView mDevicesRecyclerView;
private LinearLayout mDeviceListLayout;
private LinearLayout mCastAppLayout;
+ private LinearLayout mMediaMetadataSectionLayout;
private Button mDoneButton;
private Button mStopButton;
private Button mAppButton;
@@ -240,6 +241,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
mHeaderIcon = mDialogView.requireViewById(R.id.header_icon);
mDevicesRecyclerView = mDialogView.requireViewById(R.id.list_result);
+ mMediaMetadataSectionLayout = mDialogView.requireViewById(R.id.media_metadata_section);
mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
mDoneButton = mDialogView.requireViewById(R.id.done);
mStopButton = mDialogView.requireViewById(R.id.stop);
@@ -255,21 +257,17 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mDevicesRecyclerView.setLayoutManager(mLayoutManager);
mDevicesRecyclerView.setAdapter(mAdapter);
mDevicesRecyclerView.setHasFixedSize(false);
- // Init header icon
- mHeaderIcon.setOnClickListener(v -> onHeaderIconClick());
// Init bottom buttons
mDoneButton.setOnClickListener(v -> dismiss());
mStopButton.setOnClickListener(v -> {
mMediaOutputController.releaseSession();
dismiss();
});
- mAppButton.setOnClickListener(v -> {
- mBroadcastSender.closeSystemDialogs();
- if (mMediaOutputController.getAppLaunchIntent() != null) {
- mContext.startActivity(mMediaOutputController.getAppLaunchIntent());
- }
- dismiss();
- });
+ mAppButton.setOnClickListener(v -> mMediaOutputController.tryToLaunchMediaApplication());
+ if (mMediaOutputController.isAdvancedLayoutSupported()) {
+ mMediaMetadataSectionLayout.setOnClickListener(
+ v -> mMediaOutputController.tryToLaunchMediaApplication());
+ }
}
@Override
@@ -560,7 +558,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
@Override
public void dismissDialog() {
- dismiss();
+ mBroadcastSender.closeSystemDialogs();
}
void onHeaderIconClick() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 7bc0c0cc614b..f95da273fae6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -382,6 +382,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
return mContext.getPackageManager().getLaunchIntentForPackage(mPackageName);
}
+ void tryToLaunchMediaApplication() {
+ Intent launchIntent = getAppLaunchIntent();
+ if (launchIntent != null) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mCallback.dismissDialog();
+ mContext.startActivity(launchIntent);
+ }
+ }
+
CharSequence getHeaderTitle() {
if (mMediaController != null) {
final MediaMetadata metadata = mMediaController.getMetadata();
@@ -493,20 +502,20 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
ColorScheme mCurrentColorScheme = new ColorScheme(wallpaperColors,
isDarkTheme);
if (isDarkTheme) {
- mColorItemContent = mCurrentColorScheme.getAccent1().get(2); // A1-100
- mColorSeekbarProgress = mCurrentColorScheme.getAccent2().get(7); // A2-600
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(4); // A1-300
- mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
- mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
- mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
- mColorDialogBackground = mCurrentColorScheme.getNeutral1().get(10); // N1-900
+ mColorItemContent = mCurrentColorScheme.getAccent1().getS100(); // A1-100
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent2().getS600(); // A2-600
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().getS300(); // A1-300
+ mColorItemBackground = mCurrentColorScheme.getNeutral2().getS800(); // N2-800
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().getS800(); // A2-800
+ mColorPositiveButtonText = mCurrentColorScheme.getAccent2().getS800(); // A2-800
+ mColorDialogBackground = mCurrentColorScheme.getNeutral1().getS900(); // N1-900
} else {
- mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
- mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(7); // A1-600
- mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
- mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
- mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
+ mColorItemContent = mCurrentColorScheme.getAccent1().getS800(); // A1-800
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent1().getS300(); // A1-300
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().getS600(); // A1-600
+ mColorItemBackground = mCurrentColorScheme.getAccent2().getS50(); // A2-50
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().getS100(); // A1-100
+ mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().getS50(); // N1-50
mColorDialogBackground = mCurrentColorScheme.getBackgroundColor();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
index 8a565fa86b35..60504e43465a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
@@ -30,4 +30,8 @@ class MediaTttFlags @Inject constructor(private val featureFlags: FeatureFlags)
/** Check whether the flag for the receiver success state is enabled. */
fun isMediaTttReceiverSuccessRippleEnabled(): Boolean =
featureFlags.isEnabled(Flags.MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE)
+
+ /** True if the media transfer chip can be dismissed via a gesture. */
+ fun isMediaTttDismissGestureEnabled(): Boolean =
+ featureFlags.isEnabled(Flags.MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 889147b598b5..6884370c505c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -31,7 +31,6 @@ import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import com.android.internal.widget.CachingIconView
-import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.ui.binder.TintedIconViewBinder
@@ -78,6 +77,7 @@ open class MediaTttChipControllerReceiver @Inject constructor(
private val viewUtil: ViewUtil,
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
+ private val rippleController: MediaTttReceiverRippleController,
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger<ChipReceiverInfo>>(
context,
logger,
@@ -114,9 +114,6 @@ open class MediaTttChipControllerReceiver @Inject constructor(
}
}
- private var maxRippleWidth: Float = 0f
- private var maxRippleHeight: Float = 0f
-
private fun updateMediaTapToTransferReceiverDisplay(
@StatusBarManager.MediaTransferReceiverState displayState: Int,
routeInfo: MediaRoute2Info,
@@ -206,36 +203,40 @@ open class MediaTttChipControllerReceiver @Inject constructor(
override fun animateViewIn(view: ViewGroup) {
val appIconView = view.getAppIconView()
- appIconView.animate()
- .translationYBy(-1 * getTranslationAmount().toFloat())
- .setDuration(ICON_TRANSLATION_ANIM_DURATION)
- .start()
- appIconView.animate()
- .alpha(1f)
- .setDuration(ICON_ALPHA_ANIM_DURATION)
- .start()
+ val iconRippleView: ReceiverChipRippleView = view.requireViewById(R.id.icon_glow_ripple)
+ val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
+ animateViewTranslationAndFade(appIconView, -1 * getTranslationAmount(), 1f)
+ animateViewTranslationAndFade(iconRippleView, -1 * getTranslationAmount(), 1f)
// Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
appIconView.postOnAnimation { view.requestAccessibilityFocus() }
- expandRipple(view.requireViewById(R.id.ripple))
+ rippleController.expandToInProgressState(rippleView, iconRippleView)
}
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
val appIconView = view.getAppIconView()
- appIconView.animate()
- .translationYBy(getTranslationAmount().toFloat())
- .setDuration(ICON_TRANSLATION_ANIM_DURATION)
- .start()
- appIconView.animate()
- .alpha(0f)
- .setDuration(ICON_ALPHA_ANIM_DURATION)
- .start()
-
+ val iconRippleView: ReceiverChipRippleView = view.requireViewById(R.id.icon_glow_ripple)
val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
if (removalReason == ChipStateReceiver.TRANSFER_TO_RECEIVER_SUCCEEDED.name &&
mediaTttFlags.isMediaTttReceiverSuccessRippleEnabled()) {
- expandRippleToFull(rippleView, onAnimationEnd)
+ rippleController.expandToSuccessState(rippleView, onAnimationEnd)
+ animateViewTranslationAndFade(
+ iconRippleView,
+ -1 * getTranslationAmount(),
+ 0f,
+ translationDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ alphaDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ )
+ animateViewTranslationAndFade(
+ appIconView,
+ -1 * getTranslationAmount(),
+ 0f,
+ translationDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ alphaDuration = ICON_TRANSLATION_SUCCEEDED_DURATION,
+ )
} else {
- rippleView.collapseRipple(onAnimationEnd)
+ rippleController.collapseRipple(rippleView, onAnimationEnd)
+ animateViewTranslationAndFade(iconRippleView, getTranslationAmount(), 0f)
+ animateViewTranslationAndFade(appIconView, getTranslationAmount(), 0f)
}
}
@@ -245,74 +246,41 @@ open class MediaTttChipControllerReceiver @Inject constructor(
viewUtil.setRectToViewWindowLocation(view.getAppIconView(), outRect)
}
- /** Returns the amount that the chip will be translated by in its intro animation. */
- private fun getTranslationAmount(): Int {
- return context.resources.getDimensionPixelSize(R.dimen.media_ttt_receiver_vert_translation)
- }
-
- private fun expandRipple(rippleView: ReceiverChipRippleView) {
- if (rippleView.rippleInProgress()) {
- // Skip if ripple is still playing
- return
- }
-
- // In case the device orientation changes, we need to reset the layout.
- rippleView.addOnLayoutChangeListener (
- View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
- if (v == null) return@OnLayoutChangeListener
-
- val layoutChangedRippleView = v as ReceiverChipRippleView
- layoutRipple(layoutChangedRippleView)
- layoutChangedRippleView.invalidate()
- }
- )
- rippleView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
- override fun onViewDetachedFromWindow(view: View?) {}
-
- override fun onViewAttachedToWindow(view: View?) {
- if (view == null) {
- return
- }
- val attachedRippleView = view as ReceiverChipRippleView
- layoutRipple(attachedRippleView)
- attachedRippleView.expandRipple()
- attachedRippleView.removeOnAttachStateChangeListener(this)
- }
- })
+ /** Animation of view translation and fading. */
+ private fun animateViewTranslationAndFade(
+ view: View,
+ translationYBy: Float,
+ alphaEndValue: Float,
+ translationDuration: Long = ICON_TRANSLATION_ANIM_DURATION,
+ alphaDuration: Long = ICON_ALPHA_ANIM_DURATION,
+ ) {
+ view.animate()
+ .translationYBy(translationYBy)
+ .setDuration(translationDuration)
+ .start()
+ view.animate()
+ .alpha(alphaEndValue)
+ .setDuration(alphaDuration)
+ .start()
}
- private fun layoutRipple(rippleView: ReceiverChipRippleView, isFullScreen: Boolean = false) {
- val windowBounds = windowManager.currentWindowMetrics.bounds
- val height = windowBounds.height().toFloat()
- val width = windowBounds.width().toFloat()
-
- if (isFullScreen) {
- maxRippleHeight = height * 2f
- maxRippleWidth = width * 2f
- } else {
- maxRippleHeight = height / 2f
- maxRippleWidth = width / 2f
- }
- rippleView.setMaxSize(maxRippleWidth, maxRippleHeight)
- // Center the ripple on the bottom of the screen in the middle.
- rippleView.setCenter(width * 0.5f, height)
- val color = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
- rippleView.setColor(color, 70)
+ /** Returns the amount that the chip will be translated by in its intro animation. */
+ private fun getTranslationAmount(): Float {
+ return rippleController.getRippleSize() * 0.5f -
+ rippleController.getReceiverIconSize()
}
private fun View.getAppIconView(): CachingIconView {
return this.requireViewById(R.id.app_icon)
}
- private fun expandRippleToFull(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable?) {
- layoutRipple(rippleView, true)
- rippleView.expandToFull(maxRippleHeight, onAnimationEnd)
+ companion object {
+ private const val ICON_TRANSLATION_ANIM_DURATION = 500L
+ private const val ICON_TRANSLATION_SUCCEEDED_DURATION = 167L
+ private val ICON_ALPHA_ANIM_DURATION = 5.frames
}
}
-val ICON_TRANSLATION_ANIM_DURATION = 30.frames
-val ICON_ALPHA_ANIM_DURATION = 5.frames
-
data class ChipReceiverInfo(
val routeInfo: MediaRoute2Info,
val appIconDrawableOverride: Drawable?,
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverRippleController.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverRippleController.kt
new file mode 100644
index 000000000000..50138024e268
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverRippleController.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.media.taptotransfer.receiver
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.view.View
+import android.view.WindowManager
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import javax.inject.Inject
+
+/**
+ * A controller responsible for the animation of the ripples shown in media tap-to-transfer on the
+ * receiving device.
+ */
+class MediaTttReceiverRippleController
+@Inject
+constructor(
+ private val context: Context,
+ private val windowManager: WindowManager,
+) {
+
+ private var maxRippleWidth: Float = 0f
+ private var maxRippleHeight: Float = 0f
+
+ /** Expands the icon and main ripple to in-progress state */
+ fun expandToInProgressState(
+ mainRippleView: ReceiverChipRippleView,
+ iconRippleView: ReceiverChipRippleView,
+ ) {
+ expandRipple(mainRippleView, isIconRipple = false)
+ expandRipple(iconRippleView, isIconRipple = true)
+ }
+
+ private fun expandRipple(rippleView: ReceiverChipRippleView, isIconRipple: Boolean) {
+ if (rippleView.rippleInProgress()) {
+ // Skip if ripple is still playing
+ return
+ }
+
+ // In case the device orientation changes, we need to reset the layout.
+ rippleView.addOnLayoutChangeListener(
+ View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
+ if (v == null) return@OnLayoutChangeListener
+
+ val layoutChangedRippleView = v as ReceiverChipRippleView
+ if (isIconRipple) {
+ layoutIconRipple(layoutChangedRippleView)
+ } else {
+ layoutRipple(layoutChangedRippleView)
+ }
+ layoutChangedRippleView.invalidate()
+ }
+ )
+ rippleView.addOnAttachStateChangeListener(
+ object : View.OnAttachStateChangeListener {
+ override fun onViewDetachedFromWindow(view: View?) {}
+
+ override fun onViewAttachedToWindow(view: View?) {
+ if (view == null) {
+ return
+ }
+ val attachedRippleView = view as ReceiverChipRippleView
+ if (isIconRipple) {
+ layoutIconRipple(attachedRippleView)
+ } else {
+ layoutRipple(attachedRippleView)
+ }
+ attachedRippleView.expandRipple()
+ attachedRippleView.removeOnAttachStateChangeListener(this)
+ }
+ }
+ )
+ }
+
+ /** Expands the ripple to cover the screen. */
+ fun expandToSuccessState(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable?) {
+ layoutRipple(rippleView, isFullScreen = true)
+ rippleView.expandToFull(maxRippleHeight, onAnimationEnd)
+ }
+
+ /** Collapses the ripple. */
+ fun collapseRipple(rippleView: ReceiverChipRippleView, onAnimationEnd: Runnable? = null) {
+ rippleView.collapseRipple(onAnimationEnd)
+ }
+
+ private fun layoutRipple(rippleView: ReceiverChipRippleView, isFullScreen: Boolean = false) {
+ val windowBounds = windowManager.currentWindowMetrics.bounds
+ val height = windowBounds.height().toFloat()
+ val width = windowBounds.width().toFloat()
+
+ if (isFullScreen) {
+ maxRippleHeight = height * 2f
+ maxRippleWidth = width * 2f
+ } else {
+ maxRippleHeight = getRippleSize()
+ maxRippleWidth = getRippleSize()
+ }
+ rippleView.setMaxSize(maxRippleWidth, maxRippleHeight)
+ // Center the ripple on the bottom of the screen in the middle.
+ rippleView.setCenter(width * 0.5f, height)
+ rippleView.setColor(getRippleColor(), RIPPLE_OPACITY)
+ }
+
+ private fun layoutIconRipple(iconRippleView: ReceiverChipRippleView) {
+ val windowBounds = windowManager.currentWindowMetrics.bounds
+ val height = windowBounds.height().toFloat()
+ val width = windowBounds.width().toFloat()
+ val radius = getReceiverIconSize().toFloat()
+
+ iconRippleView.setMaxSize(radius * 0.8f, radius * 0.8f)
+ iconRippleView.setCenter(
+ width * 0.5f,
+ height - getReceiverIconSize() * 0.5f - getReceiverIconBottomMargin()
+ )
+ iconRippleView.setColor(getRippleColor(), RIPPLE_OPACITY)
+ }
+
+ private fun getRippleColor(): Int {
+ var colorStateList =
+ ColorStateList.valueOf(
+ Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
+ )
+ return colorStateList.withLStar(TONE_PERCENT).defaultColor
+ }
+
+ /** Returns the size of the ripple. */
+ internal fun getRippleSize(): Float {
+ return getReceiverIconSize() * 4f
+ }
+
+ /** Returns the size of the icon of the receiver. */
+ internal fun getReceiverIconSize(): Int {
+ return context.resources.getDimensionPixelSize(R.dimen.media_ttt_icon_size_receiver)
+ }
+
+ /** Return the bottom margin of the icon of the receiver. */
+ internal fun getReceiverIconBottomMargin(): Int {
+ // Adding a margin to make sure ripple behind the icon is not cut by the screen bounds.
+ return context.resources.getDimensionPixelSize(
+ R.dimen.media_ttt_receiver_icon_bottom_margin
+ )
+ }
+
+ companion object {
+ const val RIPPLE_OPACITY = 70
+ const val TONE_PERCENT = 95f
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
index 87b2528f93d3..f8785fcf5de0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
@@ -33,14 +33,14 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
private var isStarted: Boolean
init {
- setupShader(RippleShader.RippleShape.ELLIPSE)
+ setupShader(RippleShader.RippleShape.CIRCLE)
setRippleFill(true)
setSparkleStrength(0f)
- duration = 3000L
isStarted = false
}
fun expandRipple(onAnimationEnd: Runnable? = null) {
+ duration = DEFAULT_DURATION
isStarted = true
super.startRipple(onAnimationEnd)
}
@@ -50,6 +50,7 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
if (!isStarted) {
return // Ignore if ripple is not started yet.
}
+ duration = DEFAULT_DURATION
// Reset all listeners to animator.
animator.removeAllListeners()
animator.addListener(object : AnimatorListenerAdapter() {
@@ -74,6 +75,7 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
setRippleFill(false)
val startingPercentage = calculateStartingPercentage(newHeight)
+ animator.duration = EXPAND_TO_FULL_DURATION
animator.addUpdateListener { updateListener ->
val now = updateListener.currentPlayTime
val progress = updateListener.animatedValue as Float
@@ -100,4 +102,9 @@ class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleVi
val remainingPercentage = (1 - ratio).toDouble().pow(1 / 3.toDouble()).toFloat()
return 1 - remainingPercentage
}
+
+ companion object {
+ const val DEFAULT_DURATION = 333L
+ const val EXPAND_TO_FULL_DURATION = 1000L
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
index 935f38de2e4f..902a10a0cea9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
@@ -30,6 +30,7 @@ import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.common.MediaTttUtils
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.ViewPriority
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.ChipbarEndItem
@@ -54,6 +55,7 @@ constructor(
private var displayedState: ChipStateSender? = null
// A map to store current chip state per id.
+ // TODO(b/265455911): Log whenever we add or remove from the store.
private var stateMap: MutableMap<String, ChipStateSender> = mutableMapOf()
private val commandQueueCallbacks =
@@ -102,10 +104,9 @@ constructor(
}
uiEventLogger.logSenderStateChange(chipState)
- stateMap.put(routeInfo.id, chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
// No need to store the state since it is the default state
- stateMap.remove(routeInfo.id)
+ removeIdFromStore(routeInfo.id)
// Return early if we're not displaying a chip anyway
val currentDisplayedState = displayedState ?: return
@@ -126,7 +127,9 @@ constructor(
displayedState = null
chipbarCoordinator.removeView(routeInfo.id, removalReason)
} else {
+ stateMap[routeInfo.id] = chipState
displayedState = chipState
+ chipbarCoordinator.registerListener(displayListener)
chipbarCoordinator.displayView(
createChipbarInfo(
chipState,
@@ -135,7 +138,7 @@ constructor(
context,
logger,
)
- ) { stateMap.remove(routeInfo.id) }
+ )
}
}
@@ -182,6 +185,7 @@ constructor(
}
},
vibrationEffect = chipStateSender.transferStatus.vibrationEffect,
+ allowSwipeToDismiss = true,
windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER,
wakeReason = MediaTttUtils.WAKE_REASON_SENDER,
timeoutMs = chipStateSender.timeout,
@@ -225,4 +229,14 @@ constructor(
onClickListener,
)
}
+
+ private val displayListener =
+ TemporaryViewDisplayController.Listener { id -> removeIdFromStore(id) }
+
+ private fun removeIdFromStore(id: String) {
+ stateMap.remove(id)
+ if (stateMap.isEmpty()) {
+ chipbarCoordinator.unregisterListener(displayListener)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index a92203ca74fa..1121e160c353 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -297,7 +297,7 @@ public final class NavBarHelper implements
private void updateAssistantAvailability() {
boolean assistantAvailableForUser = mAssistManagerLazy.get()
- .getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
+ .getAssistInfoForUser(mUserTracker.getUserId()) != null;
boolean longPressDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 61bb858ee7d7..5993e2eaadad 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -72,7 +72,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
import android.text.TextUtils;
@@ -1477,7 +1476,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
final String chooserClassName = AccessibilityButtonChooserActivity.class.getName();
intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ mContext.startActivityAsUser(intent, mUserTracker.getUserHandle());
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 5d43c5dc19fa..dce69bb7ac1e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -24,7 +24,6 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -63,8 +62,8 @@ import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.pip.Pip;
@@ -87,6 +86,7 @@ public class NavigationBarController implements
private final Handler mHandler;
private final NavigationBarComponent.Factory mNavigationBarComponentFactory;
private FeatureFlags mFeatureFlags;
+ private final SecureSettings mSecureSettings;
private final DisplayManager mDisplayManager;
private final TaskbarDelegate mTaskbarDelegate;
private int mNavMode;
@@ -118,11 +118,13 @@ public class NavigationBarController implements
TaskStackChangeListeners taskStackChangeListeners,
Optional<Pip> pipOptional,
Optional<BackAnimation> backAnimation,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ SecureSettings secureSettings) {
mContext = context;
mHandler = mainHandler;
mNavigationBarComponentFactory = navigationBarComponentFactory;
mFeatureFlags = featureFlags;
+ mSecureSettings = secureSettings;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
commandQueue.addCallback(this);
configurationController.addCallback(this);
@@ -192,8 +194,7 @@ public class NavigationBarController implements
}
private void updateAccessibilityButtonModeIfNeeded() {
- ContentResolver contentResolver = mContext.getContentResolver();
- final int mode = Settings.Secure.getIntForUser(contentResolver,
+ final int mode = mSecureSettings.getIntForUser(
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
@@ -207,14 +208,14 @@ public class NavigationBarController implements
// force update to ACCESSIBILITY_BUTTON_MODE_GESTURE.
if (QuickStepContract.isGesturalMode(mNavMode)
&& mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) {
- Settings.Secure.putIntForUser(contentResolver,
+ mSecureSettings.putIntForUser(
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE,
UserHandle.USER_CURRENT);
// ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to
// force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR.
} else if (!QuickStepContract.isGesturalMode(mNavMode)
&& mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) {
- Settings.Secure.putIntForUser(contentResolver,
+ mSecureSettings.putIntForUser(
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 13c5b48906c5..eea0e4cd94b9 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -273,7 +273,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
@Override
public void triggerBack() {
// Notify FalsingManager that an intentional gesture has occurred.
- // TODO(b/186519446): use a different method than isFalseTouch
mFalsingManager.isFalseTouch(BACK_GESTURE);
// Only inject back keycodes when ahead-of-time back dispatching is disabled.
if (mBackAnimation == null) {
@@ -502,6 +501,15 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
}
private void updateIsEnabled() {
+ try {
+ Trace.beginSection("EdgeBackGestureHandler#updateIsEnabled");
+ updateIsEnabledTraced();
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private void updateIsEnabledTraced() {
boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
if (isEnabled == mIsEnabled) {
return;
@@ -587,13 +595,18 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
}
private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
- if (mEdgeBackPlugin != null) {
- mEdgeBackPlugin.onDestroy();
+ try {
+ Trace.beginSection("setEdgeBackPlugin");
+ if (mEdgeBackPlugin != null) {
+ mEdgeBackPlugin.onDestroy();
+ }
+ mEdgeBackPlugin = edgeBackPlugin;
+ mEdgeBackPlugin.setBackCallback(mBackCallback);
+ mEdgeBackPlugin.setLayoutParams(createLayoutParams());
+ updateDisplaySize();
+ } finally {
+ Trace.endSection();
}
- mEdgeBackPlugin = edgeBackPlugin;
- mEdgeBackPlugin.setBackCallback(mBackCallback);
- mEdgeBackPlugin.setLayoutParams(createLayoutParams());
- updateDisplaySize();
}
public boolean isHandlingGestures() {
@@ -919,6 +932,10 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
mThresholdCrossed = true;
// Capture inputs
mInputMonitor.pilferPointers();
+ if (mBackAnimation != null) {
+ // Notify FalsingManager that an intentional gesture has occurred.
+ mFalsingManager.isFalseTouch(BACK_GESTURE);
+ }
mInputEventReceiver.setBatchingEnabled(true);
} else {
logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE);
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
index 26e3f49828c7..4b10d69a2b80 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
@@ -72,6 +72,9 @@ constructor(
companion object {
// TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
+
+ // TODO(b/265912743): Use RoleManager.NOTES_ROLE instead.
+ const val NOTE_ROLE = "android.app.role.NOTES"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index 8bdf3195d53b..22ce12132124 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -18,11 +18,13 @@ package com.android.systemui.notetask
import android.app.Activity
import android.app.KeyguardManager
+import android.app.role.RoleManager
import android.content.Context
import android.os.UserManager
import androidx.core.content.getSystemService
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceModule
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
import dagger.Binds
@@ -33,20 +35,25 @@ import dagger.multibindings.IntoMap
import java.util.Optional
/** Compose all dependencies required by Note Task feature. */
-@Module
+@Module(includes = [NoteTaskQuickAffordanceModule::class])
internal interface NoteTaskModule {
@[Binds IntoMap ClassKey(LaunchNoteTaskActivity::class)]
- fun bindNoteTaskLauncherActivity(activity: LaunchNoteTaskActivity): Activity?
+ fun LaunchNoteTaskActivity.bindNoteTaskLauncherActivity(): Activity
@[Binds IntoMap ClassKey(CreateNoteTaskShortcutActivity::class)]
- fun bindNoteTaskShortcutActivity(activity: CreateNoteTaskShortcutActivity): Activity?
+ fun CreateNoteTaskShortcutActivity.bindNoteTaskShortcutActivity(): Activity
companion object {
@[Provides NoteTaskEnabledKey]
- fun provideIsNoteTaskEnabled(featureFlags: FeatureFlags): Boolean {
- return featureFlags.isEnabled(Flags.NOTE_TASKS)
+ fun provideIsNoteTaskEnabled(
+ featureFlags: FeatureFlags,
+ roleManager: RoleManager,
+ ): Boolean {
+ val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.NOTE_ROLE)
+ val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS)
+ return isRoleAvailable && isFeatureEnabled
}
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
new file mode 100644
index 000000000000..cfbaa48a4fa4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.notetask.quickaffordance
+
+import android.content.Context
+import com.android.systemui.R
+import com.android.systemui.animation.Expandable
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
+import com.android.systemui.notetask.NoteTaskController
+import com.android.systemui.notetask.NoteTaskEnabledKey
+import javax.inject.Inject
+import kotlinx.coroutines.flow.flowOf
+
+internal class NoteTaskQuickAffordanceConfig
+@Inject
+constructor(
+ context: Context,
+ private val noteTaskController: NoteTaskController,
+ @NoteTaskEnabledKey private val isEnabled: Boolean,
+) : KeyguardQuickAffordanceConfig {
+
+ override val key = BuiltInKeyguardQuickAffordanceKeys.CREATE_NOTE
+
+ override val pickerName: String = context.getString(R.string.note_task_button_label)
+
+ override val pickerIconResourceId = R.drawable.ic_note_task_shortcut_keyguard
+
+ override val lockScreenState = flowOf(getLockScreenState())
+
+ // TODO(b/265949213)
+ private fun getLockScreenState() =
+ if (isEnabled) {
+ val icon = Icon.Resource(pickerIconResourceId, ContentDescription.Loaded(pickerName))
+ LockScreenState.Visible(icon)
+ } else {
+ LockScreenState.Hidden
+ }
+
+ override suspend fun getPickerScreenState() =
+ if (isEnabled) {
+ PickerScreenState.Default()
+ } else {
+ PickerScreenState.UnavailableOnDevice
+ }
+
+ override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
+ noteTaskController.showNoteTask()
+ return OnTriggeredResult.Handled
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceModule.kt
new file mode 100644
index 000000000000..7cb932aa1916
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceModule.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.notetask.quickaffordance
+
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+
+@Module
+internal interface NoteTaskQuickAffordanceModule {
+
+ @[Binds IntoSet]
+ fun NoteTaskQuickAffordanceConfig.bindNoteTaskQuickAffordance(): KeyguardQuickAffordanceConfig
+}
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 f6a623e4f001..6ab0da6fe3b3 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
@@ -46,7 +46,7 @@ internal class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentA
id = SHORTCUT_ID,
shortLabel = getString(R.string.note_task_button_label),
intent = LaunchNoteTaskActivity.newIntent(context = this),
- iconResource = R.drawable.ic_note_task_button,
+ iconResource = R.drawable.ic_note_task_shortcut_widget,
)
setResult(Activity.RESULT_OK, intent)
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 90fc1d7ed49e..595b88241aae 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -68,6 +68,7 @@ import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.NotificationChannels;
@@ -175,7 +176,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private ActivityStarter mActivityStarter;
private final BroadcastSender mBroadcastSender;
private final UiEventLogger mUiEventLogger;
-
+ private final UserTracker mUserTracker;
private final Lazy<BatteryController> mBatteryControllerLazy;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -184,7 +185,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
@Inject
public PowerNotificationWarnings(Context context, ActivityStarter activityStarter,
BroadcastSender broadcastSender, Lazy<BatteryController> batteryControllerLazy,
- DialogLaunchAnimator dialogLaunchAnimator, UiEventLogger uiEventLogger) {
+ DialogLaunchAnimator dialogLaunchAnimator, UiEventLogger uiEventLogger,
+ UserTracker userTracker) {
mContext = context;
mNoMan = mContext.getSystemService(NotificationManager.class);
mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -196,6 +198,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
mDialogLaunchAnimator = dialogLaunchAnimator;
mUseSevereDialog = mContext.getResources().getBoolean(R.bool.config_severe_battery_dialog);
mUiEventLogger = uiEventLogger;
+ mUserTracker = userTracker;
}
@Override
@@ -692,7 +695,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
Secure.putIntForUser(
resolver,
Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
- 1, UserHandle.USER_CURRENT);
+ 1, mUserTracker.getUserId());
});
} else {
d.setTitle(R.string.battery_saver_confirmation_title);
@@ -843,7 +846,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
logEvent(BatteryWarningEvents
.LowBatteryWarningEvent.LOW_BATTERY_NOTIFICATION_SETTINGS);
dismissLowBatteryNotification();
- mContext.startActivityAsUser(mOpenBatterySaverSettings, UserHandle.CURRENT);
+ mContext.startActivityAsUser(mOpenBatterySaverSettings,
+ mUserTracker.getUserHandle());
} else if (action.equals(ACTION_START_SAVER)) {
logEvent(BatteryWarningEvents
.LowBatteryWarningEvent.LOW_BATTERY_NOTIFICATION_TURN_ON);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
index 39d081da43cb..36dc7433df0a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
@@ -83,8 +83,7 @@ public class ReduceBrightColorsController implements
if (mListeners.size() > 0) {
mSecureSettings.unregisterContentObserver(mContentObserver);
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(
- Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
false, mContentObserver, newUser);
}
}
@@ -100,8 +99,7 @@ public class ReduceBrightColorsController implements
mListeners.add(listener);
if (mListeners.size() == 1) {
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(
- Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
false, mContentObserver, mUserTracker.getUserId());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 4d005bebd99e..1151475f0fc3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -21,7 +21,6 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
-import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
@@ -44,8 +43,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.graphics.Insets;
-import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
import android.os.Binder;
@@ -77,6 +74,7 @@ import com.android.internal.app.IVoiceInteractionSessionListener;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.ScreenshotHelper;
+import com.android.internal.util.ScreenshotRequest;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -94,7 +92,6 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
-import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -311,7 +308,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ mContext.startActivityAsUser(intent, mUserTracker.getUserHandle());
});
}
@@ -322,18 +319,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
@Override
- public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
- Insets visibleInsets, Task.TaskKey task) {
- mScreenshotHelper.provideScreenshot(
- screenImageBundle,
- locationInScreen,
- visibleInsets,
- task.id,
- task.userId,
- task.sourceComponent,
- SCREENSHOT_OVERVIEW,
- mHandler,
- null);
+ public void takeScreenshot(ScreenshotRequest request) {
+ mScreenshotHelper.takeScreenshot(request, mHandler, null);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 5450db98af52..d64b33bb3eb1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -49,6 +49,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.screenshot.ScrollCaptureController.LongScreenshot;
+import com.android.systemui.settings.UserTracker;
import com.google.common.util.concurrent.ListenableFuture;
@@ -79,6 +80,7 @@ public class LongScreenshotActivity extends Activity {
private final LongScreenshotData mLongScreenshotHolder;
private final ActionIntentExecutor mActionExecutor;
private final FeatureFlags mFeatureFlags;
+ private final UserTracker mUserTracker;
private ImageView mPreview;
private ImageView mTransitionView;
@@ -110,7 +112,7 @@ public class LongScreenshotActivity extends Activity {
public LongScreenshotActivity(UiEventLogger uiEventLogger, ImageExporter imageExporter,
@Main Executor mainExecutor, @Background Executor bgExecutor,
LongScreenshotData longScreenshotHolder, ActionIntentExecutor actionExecutor,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags, UserTracker userTracker) {
mUiEventLogger = uiEventLogger;
mUiExecutor = mainExecutor;
mBackgroundExecutor = bgExecutor;
@@ -118,6 +120,7 @@ public class LongScreenshotActivity extends Activity {
mLongScreenshotHolder = longScreenshotHolder;
mActionExecutor = actionExecutor;
mFeatureFlags = featureFlags;
+ mUserTracker = userTracker;
}
@@ -375,7 +378,7 @@ public class LongScreenshotActivity extends Activity {
Intent sharingChooserIntent = Intent.createChooser(intent, null)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- startActivityAsUser(sharingChooserIntent, UserHandle.CURRENT);
+ startActivityAsUser(sharingChooserIntent, mUserTracker.getUserHandle());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index 95cc0dcadfb4..f011aab9da0f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -19,27 +19,26 @@ package com.android.systemui.screenshot
import android.graphics.Insets
import android.util.Log
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
-import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
+import com.android.internal.util.ScreenshotRequest
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
-import java.util.function.Consumer
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
+import java.util.function.Consumer
+import javax.inject.Inject
/**
* Processes a screenshot request sent from {@link ScreenshotHelper}.
*/
@SysUISingleton
class RequestProcessor @Inject constructor(
- private val capture: ImageCapture,
- private val policy: ScreenshotPolicy,
- private val flags: FeatureFlags,
- /** For the Java Async version, to invoke the callback. */
- @Application private val mainScope: CoroutineScope
+ private val capture: ImageCapture,
+ private val policy: ScreenshotPolicy,
+ private val flags: FeatureFlags,
+ /** For the Java Async version, to invoke the callback. */
+ @Application private val mainScope: CoroutineScope
) {
/**
* Inspects the incoming request, returning a potentially modified request depending on policy.
@@ -58,7 +57,7 @@ class RequestProcessor @Inject constructor(
// regardless of the managed profile status.
if (request.type != TAKE_SCREENSHOT_PROVIDED_IMAGE &&
- flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
+ flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
) {
val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
@@ -66,17 +65,21 @@ class RequestProcessor @Inject constructor(
result = if (policy.isManagedProfile(info.user.identifier)) {
val image = capture.captureTask(info.taskId)
- ?: error("Task snapshot returned a null Bitmap!")
+ ?: error("Task snapshot returned a null Bitmap!")
// Provide the task snapshot as the screenshot
- ScreenshotRequest(
- TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source,
- HardwareBitmapBundler.hardwareBitmapToBundle(image),
- info.bounds, Insets.NONE, info.taskId, info.user.identifier, info.component
- )
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source)
+ .setTopComponent(info.component)
+ .setTaskId(info.taskId)
+ .setUserId(info.user.identifier)
+ .setBitmap(image)
+ .setBoundsOnScreen(info.bounds)
+ .setInsets(Insets.NONE)
+ .build()
} else {
// Create a new request of the same type which includes the top component
- ScreenshotRequest(request.type, request.source, info.component)
+ ScreenshotRequest.Builder(request.type, request.source)
+ .setTopComponent(info.component).build()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index b21a4857c736..6d87922f49eb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -416,10 +416,11 @@ public class ScreenshotController {
}
boolean showFlash = false;
- if (!aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
+ if (screenshotScreenBounds == null
+ || !aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
showFlash = true;
visibleInsets = Insets.NONE;
- screenshotScreenBounds.set(0, 0, screenshot.getWidth(), screenshot.getHeight());
+ screenshotScreenBounds = new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight());
}
mCurrentRequestCallback = requestCallback;
saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, topComponent,
@@ -553,6 +554,10 @@ public class ScreenshotController {
Log.d(TAG, "adding OnComputeInternalInsetsListener");
}
mScreenshotView.getViewTreeObserver().addOnComputeInternalInsetsListener(mScreenshotView);
+ if (DEBUG_WINDOW) {
+ Log.d(TAG, "setContentView: " + mScreenshotView);
+ }
+ setContentView(mScreenshotView);
}
/**
@@ -634,6 +639,7 @@ public class ScreenshotController {
// The window is focusable by default
setWindowFocusable(true);
+ mScreenshotView.requestFocus();
// Wait until this window is attached to request because it is
// the reference used to locate the target window (below).
@@ -691,10 +697,7 @@ public class ScreenshotController {
mContext.getDrawable(R.drawable.overlay_badge_background), owner));
}
mScreenshotView.setScreenshot(mScreenBitmap, screenInsets);
- if (DEBUG_WINDOW) {
- Log.d(TAG, "setContentView: " + mScreenshotView);
- }
- setContentView(mScreenshotView);
+
// ignore system bar insets for the purpose of window layout
mWindow.getDecorView().setOnApplyWindowInsetsListener(
(v, insets) -> WindowInsets.CONSUMED);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 35e9f3e56723..7b271a886d68 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -54,7 +54,7 @@ import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.util.ScreenshotHelper;
+import com.android.internal.util.ScreenshotRequest;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.flags.FeatureFlags;
@@ -186,8 +186,7 @@ public class TakeScreenshotService extends Service {
final Consumer<Uri> onSaved = (uri) -> reportUri(replyTo, uri);
RequestCallback callback = new RequestCallbackImpl(replyTo);
- ScreenshotHelper.ScreenshotRequest request =
- (ScreenshotHelper.ScreenshotRequest) msg.obj;
+ ScreenshotRequest request = (ScreenshotRequest) msg.obj;
handleRequest(request, onSaved, callback);
return true;
@@ -195,7 +194,7 @@ public class TakeScreenshotService extends Service {
@MainThread
@VisibleForTesting
- void handleRequest(ScreenshotHelper.ScreenshotRequest request, Consumer<Uri> onSaved,
+ void handleRequest(ScreenshotRequest request, Consumer<Uri> onSaved,
RequestCallback callback) {
// If the storage for this user is locked, we have no place to store
// the screenshot, so skip taking it instead of showing a misleading
@@ -226,7 +225,7 @@ public class TakeScreenshotService extends Service {
(r) -> dispatchToController(r, onSaved, callback));
}
- private void dispatchToController(ScreenshotHelper.ScreenshotRequest request,
+ private void dispatchToController(ScreenshotRequest request,
Consumer<Uri> uriConsumer, RequestCallback callback) {
ComponentName topComponent = request.getTopComponent();
@@ -244,8 +243,7 @@ public class TakeScreenshotService extends Service {
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
}
- Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap(
- request.getBitmapBundle());
+ Bitmap screenshot = request.getBitmap();
Rect screenBounds = request.getBoundsInScreen();
Insets insets = request.getInsets();
int taskId = request.getTaskId();
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 5880003cdb1a..2f6081bc9f8d 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -218,7 +218,7 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
- UserHandle.USER_CURRENT);
+ mUserTracker.getUserId());
mAutomatic = automatic != Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
index 5011227ad2cc..b3d31f2986d1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
@@ -69,7 +69,8 @@ object CombinedShadeHeadersConstraintManagerImpl : CombinedShadeHeadersConstrain
}
return ConstraintsChanges(
qqsConstraintsChanges = change,
- qsConstraintsChanges = change
+ qsConstraintsChanges = change,
+ largeScreenConstraintsChanges = change,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index e406be1ea0a3..88676371bd6b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -113,7 +113,7 @@ class LargeScreenShadeHeaderController @Inject constructor(
QQS_HEADER_CONSTRAINT -> "QQS Header"
QS_HEADER_CONSTRAINT -> "QS Header"
LARGE_SCREEN_HEADER_CONSTRAINT -> "Large Screen Header"
- else -> "Unknown state"
+ else -> "Unknown state $this"
}
}
@@ -296,6 +296,9 @@ class LargeScreenShadeHeaderController @Inject constructor(
override fun onViewAttached() {
privacyIconsController.chipVisibilityListener = chipVisibilityListener
+ updateVisibility()
+ updateTransition()
+
if (header is MotionLayout) {
header.setOnApplyWindowInsetsListener(insetListener)
clock.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
@@ -308,9 +311,6 @@ class LargeScreenShadeHeaderController @Inject constructor(
dumpManager.registerDumpable(this)
configurationController.addCallback(configurationControllerListener)
demoModeController.addCallback(demoModeReceiver)
-
- updateVisibility()
- updateTransition()
}
override fun onViewDetached() {
@@ -436,15 +436,14 @@ class LargeScreenShadeHeaderController @Inject constructor(
header as MotionLayout
if (largeScreenActive) {
logInstantEvent("Large screen constraints set")
- header.setTransition(HEADER_TRANSITION_ID)
- header.transitionToStart()
+ header.setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID)
} else {
logInstantEvent("Small screen constraints set")
header.setTransition(HEADER_TRANSITION_ID)
- header.transitionToStart()
- updatePosition()
- updateScrollY()
}
+ header.jumpToState(header.startState)
+ updatePosition()
+ updateScrollY()
}
private fun updatePosition() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c0017bee053b..392a851290de 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -450,6 +450,7 @@ public final class NotificationPanelViewController implements Dumpable {
private float mDownY;
private int mDisplayTopInset = 0; // in pixels
private int mDisplayRightInset = 0; // in pixels
+ private int mDisplayLeftInset = 0; // in pixels
private int mLargeScreenShadeHeaderHeight;
private int mSplitShadeNotificationsScrimMarginBottom;
@@ -2096,7 +2097,17 @@ public final class NotificationPanelViewController implements Dumpable {
}
}
- public void expandWithoutQs() {
+ /**
+ * Expand shade so that notifications are visible.
+ * Non-split shade: just expanding shade or collapsing QS when they're expanded.
+ * Split shade: only expanding shade, notifications are always visible
+ *
+ * Called when `adb shell cmd statusbar expand-notifications` is executed.
+ */
+ public void expandShadeToNotifications() {
+ if (mSplitShadeEnabled && (isShadeFullyOpen() || isExpanding())) {
+ return;
+ }
if (isQsExpanded()) {
flingSettings(0 /* velocity */, FLING_COLLAPSE);
} else {
@@ -3011,7 +3022,7 @@ public final class NotificationPanelViewController implements Dumpable {
// left bounds can ignore insets, it should always reach the edge of the screen
return 0;
} else {
- return mNotificationStackScrollLayoutController.getLeft();
+ return mNotificationStackScrollLayoutController.getLeft() + mDisplayLeftInset;
}
}
@@ -3019,7 +3030,7 @@ public final class NotificationPanelViewController implements Dumpable {
if (mIsFullWidth) {
return mView.getRight() + mDisplayRightInset;
} else {
- return mNotificationStackScrollLayoutController.getRight();
+ return mNotificationStackScrollLayoutController.getRight() + mDisplayLeftInset;
}
}
@@ -3143,8 +3154,8 @@ public final class NotificationPanelViewController implements Dumpable {
// Convert global clipping coordinates to local ones,
// relative to NotificationStackScrollLayout
- int nsslLeft = left - mNotificationStackScrollLayoutController.getLeft();
- int nsslRight = right - mNotificationStackScrollLayoutController.getLeft();
+ int nsslLeft = calculateNsslLeft(left);
+ int nsslRight = calculateNsslRight(right);
int nsslTop = getNotificationsClippingTopBounds(top);
int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
int bottomRadius = mSplitShadeEnabled ? radius : 0;
@@ -3153,6 +3164,22 @@ public final class NotificationPanelViewController implements Dumpable {
nsslLeft, nsslTop, nsslRight, nsslBottom, topRadius, bottomRadius);
}
+ private int calculateNsslLeft(int nsslLeftAbsolute) {
+ int left = nsslLeftAbsolute - mNotificationStackScrollLayoutController.getLeft();
+ if (mIsFullWidth) {
+ return left;
+ }
+ return left - mDisplayLeftInset;
+ }
+
+ private int calculateNsslRight(int nsslRightAbsolute) {
+ int right = nsslRightAbsolute - mNotificationStackScrollLayoutController.getLeft();
+ if (mIsFullWidth) {
+ return right;
+ }
+ return right - mDisplayLeftInset;
+ }
+
private int getNotificationsClippingTopBounds(int qsTop) {
if (mSplitShadeEnabled && mExpandingFromHeadsUp) {
// in split shade nssl has extra top margin so clipping at top 0 is not enough, we need
@@ -4169,9 +4196,7 @@ public final class NotificationPanelViewController implements Dumpable {
}
private void updateStatusBarIcons() {
- boolean showIconsWhenExpanded =
- (isPanelVisibleBecauseOfHeadsUp() || mIsFullWidth)
- && getExpandedHeight() < getOpeningHeight();
+ boolean showIconsWhenExpanded = getExpandedHeight() < getOpeningHeight();
if (showIconsWhenExpanded && isOnKeyguard()) {
showIconsWhenExpanded = false;
}
@@ -4238,7 +4263,7 @@ public final class NotificationPanelViewController implements Dumpable {
&& mHeadsUpAppearanceController.shouldBeVisible()) {
return false;
}
- return !mIsFullWidth || !mShowIconsWhenExpanded;
+ return !mShowIconsWhenExpanded;
}
private void onQsPanelScrollChanged(int scrollY) {
@@ -4550,6 +4575,7 @@ public final class NotificationPanelViewController implements Dumpable {
ipw.print("mDownY="); ipw.println(mDownY);
ipw.print("mDisplayTopInset="); ipw.println(mDisplayTopInset);
ipw.print("mDisplayRightInset="); ipw.println(mDisplayRightInset);
+ ipw.print("mDisplayLeftInset="); ipw.println(mDisplayLeftInset);
ipw.print("mLargeScreenShadeHeaderHeight="); ipw.println(mLargeScreenShadeHeaderHeight);
ipw.print("mSplitShadeNotificationsScrimMarginBottom=");
ipw.println(mSplitShadeNotificationsScrimMarginBottom);
@@ -5520,7 +5546,7 @@ public final class NotificationPanelViewController implements Dumpable {
@Override
public void flingTopOverscroll(float velocity, boolean open) {
- // in split shade mode we want to expand/collapse QS only when touch happens within QS
+ // in split shade touches affect QS only when touch happens within QS
if (isSplitShadeAndTouchXOutsideQs(mInitialTouchX)) {
return;
}
@@ -5927,6 +5953,7 @@ public final class NotificationPanelViewController implements Dumpable {
Insets combinedInsets = insets.getInsetsIgnoringVisibility(insetTypes);
mDisplayTopInset = combinedInsets.top;
mDisplayRightInset = combinedInsets.right;
+ mDisplayLeftInset = combinedInsets.left;
mNavigationBarBottomHeight = insets.getStableInsetBottom();
updateMaxHeadsUpTranslation();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 26f8b6222dc1..ab2e692915ad 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -19,6 +19,7 @@ package com.android.systemui.shade;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
@@ -52,13 +53,13 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.dump.DumpsysTableLogger;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
@@ -72,10 +73,8 @@ import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.Objects;
-import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -89,6 +88,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
Dumpable, ConfigurationListener {
private static final String TAG = "NotificationShadeWindowController";
+ private static final int MAX_STATE_CHANGES_BUFFER_SIZE = 100;
private final Context mContext;
private final WindowManager mWindowManager;
@@ -108,7 +108,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
private boolean mHasTopUi;
private boolean mHasTopUiChanged;
private float mScreenBrightnessDoze;
- private final State mCurrentState = new State();
+ private final NotificationShadeWindowState mCurrentState = new NotificationShadeWindowState();
private OtherwisedCollapsedListener mListener;
private ForcePluginOpenListener mForcePluginOpenListener;
private Consumer<Integer> mScrimsVisibilityListener;
@@ -125,6 +125,9 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
private int mDeferWindowLayoutParams;
private boolean mLastKeyguardRotationAllowed;
+ private final NotificationShadeWindowState.Buffer mStateBuffer =
+ new NotificationShadeWindowState.Buffer(MAX_STATE_CHANGES_BUFFER_SIZE);
+
@Inject
public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager,
IActivityManager activityManager, DozeParameters dozeParameters,
@@ -210,8 +213,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
@VisibleForTesting
void onShadeExpansionFullyChanged(Boolean isExpanded) {
- if (mCurrentState.mPanelExpanded != isExpanded) {
- mCurrentState.mPanelExpanded = isExpanded;
+ if (mCurrentState.panelExpanded != isExpanded) {
+ mCurrentState.panelExpanded = isExpanded;
apply(mCurrentState);
}
}
@@ -251,6 +254,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
mLp.setTitle("NotificationShade");
mLp.packageName = mContext.getPackageName();
mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mLp.privateFlags |= PRIVATE_FLAG_OPTIMIZE_MEASURE;
// We use BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE here, however, there is special logic in
// window manager which disables the transient show behavior.
@@ -296,10 +300,10 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
mNotificationShadeView.setSystemUiVisibility(vis);
}
- private void applyKeyguardFlags(State state) {
- final boolean keyguardOrAod = state.mKeyguardShowing
- || (state.mDozing && mDozeParameters.getAlwaysOn());
- if ((keyguardOrAod && !state.mBackdropShowing && !state.mLightRevealScrimOpaque)
+ private void applyKeyguardFlags(NotificationShadeWindowState state) {
+ final boolean keyguardOrAod = state.keyguardShowing
+ || (state.dozing && mDozeParameters.getAlwaysOn());
+ if ((keyguardOrAod && !state.mediaBackdropShowing && !state.lightRevealScrimOpaque)
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind()) {
// Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a
// solid backdrop. Also, show it if we are currently animating between the
@@ -310,15 +314,15 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
}
- if (state.mDozing) {
+ if (state.dozing) {
mLpChanged.privateFlags |= LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
} else {
mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
}
if (mKeyguardPreferredRefreshRate > 0) {
- boolean onKeyguard = state.mStatusBarState == StatusBarState.KEYGUARD
- && !state.mKeyguardFadingAway && !state.mKeyguardGoingAway;
+ boolean onKeyguard = state.statusBarState == StatusBarState.KEYGUARD
+ && !state.keyguardFadingAway && !state.keyguardGoingAway;
if (onKeyguard
&& mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) {
// both max and min display refresh rate must be set to take effect:
@@ -332,9 +336,9 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
(long) mKeyguardPreferredRefreshRate);
} else if (mKeyguardMaxRefreshRate > 0) {
boolean bypassOnKeyguard = mKeyguardBypassController.getBypassEnabled()
- && state.mStatusBarState == StatusBarState.KEYGUARD
- && !state.mKeyguardFadingAway && !state.mKeyguardGoingAway;
- if (state.mDozing || bypassOnKeyguard) {
+ && state.statusBarState == StatusBarState.KEYGUARD
+ && !state.keyguardFadingAway && !state.keyguardGoingAway;
+ if (state.dozing || bypassOnKeyguard) {
mLpChanged.preferredMaxDisplayRefreshRate = mKeyguardMaxRefreshRate;
} else {
mLpChanged.preferredMaxDisplayRefreshRate = 0;
@@ -343,7 +347,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
(long) mLpChanged.preferredMaxDisplayRefreshRate);
}
- if (state.mBouncerShowing && !isDebuggable()) {
+ if (state.bouncerShowing && !isDebuggable()) {
mLpChanged.flags |= LayoutParams.FLAG_SECURE;
} else {
mLpChanged.flags &= ~LayoutParams.FLAG_SECURE;
@@ -354,8 +358,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
return Build.IS_DEBUGGABLE;
}
- private void adjustScreenOrientation(State state) {
- if (state.mBouncerShowing || state.isKeyguardShowingAndNotOccluded() || state.mDozing) {
+ private void adjustScreenOrientation(NotificationShadeWindowState state) {
+ if (state.bouncerShowing || state.isKeyguardShowingAndNotOccluded() || state.dozing) {
if (mKeyguardStateController.isKeyguardScreenRotationAllowed()) {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
} else {
@@ -366,10 +370,10 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
}
- private void applyFocusableFlag(State state) {
- boolean panelFocusable = state.mNotificationShadeFocusable && state.mPanelExpanded;
- if (state.mBouncerShowing && (state.mKeyguardOccluded || state.mKeyguardNeedsInput)
- || ENABLE_REMOTE_INPUT && state.mRemoteInputActive
+ private void applyFocusableFlag(NotificationShadeWindowState state) {
+ boolean panelFocusable = state.notificationShadeFocusable && state.panelExpanded;
+ if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
+ || ENABLE_REMOTE_INPUT && state.remoteInputActive
// Make the panel focusable if we're doing the screen off animation, since the light
// reveal scrim is drawing in the panel and should consume touch events so that they
// don't go to the app behind.
@@ -379,7 +383,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
} else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
// Make sure to remove FLAG_ALT_FOCUSABLE_IM when keyguard needs input.
- if (state.mKeyguardNeedsInput && state.isKeyguardShowingAndNotOccluded()) {
+ if (state.keyguardNeedsInput && state.isKeyguardShowingAndNotOccluded()) {
mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else {
mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -390,19 +394,19 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
}
- private void applyForceShowNavigationFlag(State state) {
- if (state.mPanelExpanded || state.mBouncerShowing
- || ENABLE_REMOTE_INPUT && state.mRemoteInputActive) {
+ private void applyForceShowNavigationFlag(NotificationShadeWindowState state) {
+ if (state.panelExpanded || state.bouncerShowing
+ || ENABLE_REMOTE_INPUT && state.remoteInputActive) {
mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
} else {
mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
}
}
- private void applyVisibility(State state) {
+ private void applyVisibility(NotificationShadeWindowState state) {
boolean visible = isExpanded(state);
mLogger.logApplyVisibility(visible);
- if (state.mForcePluginOpen) {
+ if (state.forcePluginOpen) {
if (mListener != null) {
mListener.setWouldOtherwiseCollapse(visible);
}
@@ -418,16 +422,16 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
}
- private boolean isExpanded(State state) {
- return !state.mForceCollapsed && (state.isKeyguardShowingAndNotOccluded()
- || state.mPanelVisible || state.mKeyguardFadingAway || state.mBouncerShowing
- || state.mHeadsUpShowing
- || state.mScrimsVisibility != ScrimController.TRANSPARENT)
- || state.mBackgroundBlurRadius > 0
- || state.mLaunchingActivity;
+ private boolean isExpanded(NotificationShadeWindowState state) {
+ return !state.forceWindowCollapsed && (state.isKeyguardShowingAndNotOccluded()
+ || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
+ || state.headsUpNotificationShowing
+ || state.scrimsVisibility != ScrimController.TRANSPARENT)
+ || state.backgroundBlurRadius > 0
+ || state.launchingActivityFromNotification;
}
- private void applyFitsSystemWindows(State state) {
+ private void applyFitsSystemWindows(NotificationShadeWindowState state) {
boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
if (mNotificationShadeView != null
&& mNotificationShadeView.getFitsSystemWindows() != fitsSystemWindows) {
@@ -436,21 +440,21 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
}
- private void applyUserActivityTimeout(State state) {
+ private void applyUserActivityTimeout(NotificationShadeWindowState state) {
if (state.isKeyguardShowingAndNotOccluded()
- && state.mStatusBarState == StatusBarState.KEYGUARD
- && !state.mQsExpanded) {
- mLpChanged.userActivityTimeout = state.mBouncerShowing
+ && state.statusBarState == StatusBarState.KEYGUARD
+ && !state.qsExpanded) {
+ mLpChanged.userActivityTimeout = state.bouncerShowing
? KeyguardViewMediator.AWAKE_INTERVAL_BOUNCER_MS : mLockScreenDisplayTimeout;
} else {
mLpChanged.userActivityTimeout = -1;
}
}
- private void applyInputFeatures(State state) {
+ private void applyInputFeatures(NotificationShadeWindowState state) {
if (state.isKeyguardShowingAndNotOccluded()
- && state.mStatusBarState == StatusBarState.KEYGUARD
- && !state.mQsExpanded && !state.mForceUserActivity) {
+ && state.statusBarState == StatusBarState.KEYGUARD
+ && !state.qsExpanded && !state.forceUserActivity) {
mLpChanged.inputFeatures |=
LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
} else {
@@ -459,7 +463,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
}
- private void applyStatusBarColorSpaceAgnosticFlag(State state) {
+ private void applyStatusBarColorSpaceAgnosticFlag(NotificationShadeWindowState state) {
if (!isExpanded(state)) {
mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
} else {
@@ -485,8 +489,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
applyWindowLayoutParams();
}
- private void apply(State state) {
- mLogger.logNewState(state);
+ private void apply(NotificationShadeWindowState state) {
+ logState(state);
applyKeyguardFlags(state);
applyFocusableFlag(state);
applyForceShowNavigationFlag(state);
@@ -515,6 +519,38 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
notifyStateChangedCallbacks();
}
+ private void logState(NotificationShadeWindowState state) {
+ mStateBuffer.insert(
+ state.keyguardShowing,
+ state.keyguardOccluded,
+ state.keyguardNeedsInput,
+ state.panelVisible,
+ state.panelExpanded,
+ state.notificationShadeFocusable,
+ state.bouncerShowing,
+ state.keyguardFadingAway,
+ state.keyguardGoingAway,
+ state.qsExpanded,
+ state.headsUpNotificationShowing,
+ state.lightRevealScrimOpaque,
+ state.forceWindowCollapsed,
+ state.forceDozeBrightness,
+ state.forceUserActivity,
+ state.launchingActivityFromNotification,
+ state.mediaBackdropShowing,
+ state.wallpaperSupportsAmbientMode,
+ state.windowNotTouchable,
+ state.componentsForcingTopUi,
+ state.forceOpenTokens,
+ state.statusBarState,
+ state.remoteInputActive,
+ state.forcePluginOpen,
+ state.dozing,
+ state.scrimsVisibility,
+ state.backgroundBlurRadius
+ );
+ }
+
@Override
public void notifyStateChangedCallbacks() {
// Copy callbacks to separate ArrayList to avoid concurrent modification
@@ -523,36 +559,36 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
.filter(Objects::nonNull)
.collect(Collectors.toList());
for (StatusBarWindowCallback cb : activeCallbacks) {
- cb.onStateChanged(mCurrentState.mKeyguardShowing,
- mCurrentState.mKeyguardOccluded,
- mCurrentState.mBouncerShowing,
- mCurrentState.mDozing,
- mCurrentState.mPanelExpanded);
+ cb.onStateChanged(mCurrentState.keyguardShowing,
+ mCurrentState.keyguardOccluded,
+ mCurrentState.bouncerShowing,
+ mCurrentState.dozing,
+ mCurrentState.panelExpanded);
}
}
- private void applyModalFlag(State state) {
- if (state.mHeadsUpShowing) {
+ private void applyModalFlag(NotificationShadeWindowState state) {
+ if (state.headsUpNotificationShowing) {
mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCH_MODAL;
} else {
mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCH_MODAL;
}
}
- private void applyBrightness(State state) {
- if (state.mForceDozeBrightness) {
+ private void applyBrightness(NotificationShadeWindowState state) {
+ if (state.forceDozeBrightness) {
mLpChanged.screenBrightness = mScreenBrightnessDoze;
} else {
mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
}
}
- private void applyHasTopUi(State state) {
- mHasTopUiChanged = !state.mComponentsForcingTopUi.isEmpty() || isExpanded(state);
+ private void applyHasTopUi(NotificationShadeWindowState state) {
+ mHasTopUiChanged = !state.componentsForcingTopUi.isEmpty() || isExpanded(state);
}
- private void applyNotTouchable(State state) {
- if (state.mNotTouchable) {
+ private void applyNotTouchable(NotificationShadeWindowState state) {
+ if (state.windowNotTouchable) {
mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
} else {
mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -574,88 +610,88 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
@Override
public void setKeyguardShowing(boolean showing) {
- mCurrentState.mKeyguardShowing = showing;
+ mCurrentState.keyguardShowing = showing;
apply(mCurrentState);
}
@Override
public void setKeyguardOccluded(boolean occluded) {
- mCurrentState.mKeyguardOccluded = occluded;
+ mCurrentState.keyguardOccluded = occluded;
apply(mCurrentState);
}
@Override
public void setKeyguardNeedsInput(boolean needsInput) {
- mCurrentState.mKeyguardNeedsInput = needsInput;
+ mCurrentState.keyguardNeedsInput = needsInput;
apply(mCurrentState);
}
@Override
public void setPanelVisible(boolean visible) {
- if (mCurrentState.mPanelVisible == visible
- && mCurrentState.mNotificationShadeFocusable == visible) {
+ if (mCurrentState.panelVisible == visible
+ && mCurrentState.notificationShadeFocusable == visible) {
return;
}
mLogger.logShadeVisibleAndFocusable(visible);
- mCurrentState.mPanelVisible = visible;
- mCurrentState.mNotificationShadeFocusable = visible;
+ mCurrentState.panelVisible = visible;
+ mCurrentState.notificationShadeFocusable = visible;
apply(mCurrentState);
}
@Override
public void setNotificationShadeFocusable(boolean focusable) {
mLogger.logShadeFocusable(focusable);
- mCurrentState.mNotificationShadeFocusable = focusable;
+ mCurrentState.notificationShadeFocusable = focusable;
apply(mCurrentState);
}
@Override
public void setBouncerShowing(boolean showing) {
- mCurrentState.mBouncerShowing = showing;
+ mCurrentState.bouncerShowing = showing;
apply(mCurrentState);
}
@Override
public void setBackdropShowing(boolean showing) {
- mCurrentState.mBackdropShowing = showing;
+ mCurrentState.mediaBackdropShowing = showing;
apply(mCurrentState);
}
@Override
public void setKeyguardFadingAway(boolean keyguardFadingAway) {
- mCurrentState.mKeyguardFadingAway = keyguardFadingAway;
+ mCurrentState.keyguardFadingAway = keyguardFadingAway;
apply(mCurrentState);
}
private void onQsExpansionChanged(Boolean expanded) {
- mCurrentState.mQsExpanded = expanded;
+ mCurrentState.qsExpanded = expanded;
apply(mCurrentState);
}
@Override
public void setForceUserActivity(boolean forceUserActivity) {
- mCurrentState.mForceUserActivity = forceUserActivity;
+ mCurrentState.forceUserActivity = forceUserActivity;
apply(mCurrentState);
}
@Override
public void setLaunchingActivity(boolean launching) {
- mCurrentState.mLaunchingActivity = launching;
+ mCurrentState.launchingActivityFromNotification = launching;
apply(mCurrentState);
}
@Override
public boolean isLaunchingActivity() {
- return mCurrentState.mLaunchingActivity;
+ return mCurrentState.launchingActivityFromNotification;
}
@Override
public void setScrimsVisibility(int scrimsVisibility) {
- if (scrimsVisibility == mCurrentState.mScrimsVisibility) {
+ if (scrimsVisibility == mCurrentState.scrimsVisibility) {
return;
}
boolean wasExpanded = isExpanded(mCurrentState);
- mCurrentState.mScrimsVisibility = scrimsVisibility;
+ mCurrentState.scrimsVisibility = scrimsVisibility;
if (wasExpanded != isExpanded(mCurrentState)) {
apply(mCurrentState);
}
@@ -669,31 +705,31 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
*/
@Override
public void setBackgroundBlurRadius(int backgroundBlurRadius) {
- if (mCurrentState.mBackgroundBlurRadius == backgroundBlurRadius) {
+ if (mCurrentState.backgroundBlurRadius == backgroundBlurRadius) {
return;
}
- mCurrentState.mBackgroundBlurRadius = backgroundBlurRadius;
+ mCurrentState.backgroundBlurRadius = backgroundBlurRadius;
apply(mCurrentState);
}
@Override
public void setHeadsUpShowing(boolean showing) {
- mCurrentState.mHeadsUpShowing = showing;
+ mCurrentState.headsUpNotificationShowing = showing;
apply(mCurrentState);
}
@Override
public void setLightRevealScrimOpaque(boolean opaque) {
- if (mCurrentState.mLightRevealScrimOpaque == opaque) {
+ if (mCurrentState.lightRevealScrimOpaque == opaque) {
return;
}
- mCurrentState.mLightRevealScrimOpaque = opaque;
+ mCurrentState.lightRevealScrimOpaque = opaque;
apply(mCurrentState);
}
@Override
public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) {
- mCurrentState.mWallpaperSupportsAmbientMode = supportsAmbientMode;
+ mCurrentState.wallpaperSupportsAmbientMode = supportsAmbientMode;
apply(mCurrentState);
}
@@ -701,7 +737,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
* @param state The {@link StatusBarStateController} of the status bar.
*/
private void setStatusBarState(int state) {
- mCurrentState.mStatusBarState = state;
+ mCurrentState.statusBarState = state;
apply(mCurrentState);
}
@@ -712,13 +748,13 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
*/
@Override
public void setForceWindowCollapsed(boolean force) {
- mCurrentState.mForceCollapsed = force;
+ mCurrentState.forceWindowCollapsed = force;
apply(mCurrentState);
}
@Override
public void onRemoteInputActive(boolean remoteInputActive) {
- mCurrentState.mRemoteInputActive = remoteInputActive;
+ mCurrentState.remoteInputActive = remoteInputActive;
apply(mCurrentState);
}
@@ -728,32 +764,32 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
*/
@Override
public void setForceDozeBrightness(boolean forceDozeBrightness) {
- if (mCurrentState.mForceDozeBrightness == forceDozeBrightness) {
+ if (mCurrentState.forceDozeBrightness == forceDozeBrightness) {
return;
}
- mCurrentState.mForceDozeBrightness = forceDozeBrightness;
+ mCurrentState.forceDozeBrightness = forceDozeBrightness;
apply(mCurrentState);
}
@Override
public void setDozing(boolean dozing) {
- mCurrentState.mDozing = dozing;
+ mCurrentState.dozing = dozing;
apply(mCurrentState);
}
@Override
public void setForcePluginOpen(boolean forceOpen, Object token) {
if (forceOpen) {
- mCurrentState.mForceOpenTokens.add(token);
+ mCurrentState.forceOpenTokens.add(token);
} else {
- mCurrentState.mForceOpenTokens.remove(token);
+ mCurrentState.forceOpenTokens.remove(token);
}
- final boolean previousForceOpenState = mCurrentState.mForcePluginOpen;
- mCurrentState.mForcePluginOpen = !mCurrentState.mForceOpenTokens.isEmpty();
- if (previousForceOpenState != mCurrentState.mForcePluginOpen) {
+ final boolean previousForceOpenState = mCurrentState.forcePluginOpen;
+ mCurrentState.forcePluginOpen = !mCurrentState.forceOpenTokens.isEmpty();
+ if (previousForceOpenState != mCurrentState.forcePluginOpen) {
apply(mCurrentState);
if (mForcePluginOpenListener != null) {
- mForcePluginOpenListener.onChange(mCurrentState.mForcePluginOpen);
+ mForcePluginOpenListener.onChange(mCurrentState.forcePluginOpen);
}
}
}
@@ -763,12 +799,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
*/
@Override
public boolean getForcePluginOpen() {
- return mCurrentState.mForcePluginOpen;
+ return mCurrentState.forcePluginOpen;
}
@Override
public void setNotTouchable(boolean notTouchable) {
- mCurrentState.mNotTouchable = notTouchable;
+ mCurrentState.windowNotTouchable = notTouchable;
apply(mCurrentState);
}
@@ -777,7 +813,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
*/
@Override
public boolean getPanelExpanded() {
- return mCurrentState.mPanelExpanded;
+ return mCurrentState.panelExpanded;
}
@Override
@@ -800,11 +836,16 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
if (mNotificationShadeView != null && mNotificationShadeView.getViewRootImpl() != null) {
mNotificationShadeView.getViewRootImpl().dump(" ", pw);
}
+ new DumpsysTableLogger(
+ TAG,
+ NotificationShadeWindowState.TABLE_HEADERS,
+ mStateBuffer.toList()
+ ).printTableData(pw);
}
@Override
public boolean isShowingWallpaper() {
- return !mCurrentState.mBackdropShowing;
+ return !mCurrentState.mediaBackdropShowing;
}
@Override
@@ -834,7 +875,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
*/
@Override
public void setKeyguardGoingAway(boolean goingAway) {
- mCurrentState.mKeyguardGoingAway = goingAway;
+ mCurrentState.keyguardGoingAway = goingAway;
apply(mCurrentState);
}
@@ -846,87 +887,13 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
@Override
public void setRequestTopUi(boolean requestTopUi, String componentTag) {
if (requestTopUi) {
- mCurrentState.mComponentsForcingTopUi.add(componentTag);
+ mCurrentState.componentsForcingTopUi.add(componentTag);
} else {
- mCurrentState.mComponentsForcingTopUi.remove(componentTag);
+ mCurrentState.componentsForcingTopUi.remove(componentTag);
}
apply(mCurrentState);
}
- private static class State {
- boolean mKeyguardShowing;
- boolean mKeyguardOccluded;
- boolean mKeyguardNeedsInput;
- boolean mPanelVisible;
- boolean mPanelExpanded;
- boolean mNotificationShadeFocusable;
- boolean mBouncerShowing;
- boolean mKeyguardFadingAway;
- boolean mKeyguardGoingAway;
- boolean mQsExpanded;
- boolean mHeadsUpShowing;
- boolean mLightRevealScrimOpaque;
- boolean mForceCollapsed;
- boolean mForceDozeBrightness;
- boolean mForceUserActivity;
- boolean mLaunchingActivity;
- boolean mBackdropShowing;
- boolean mWallpaperSupportsAmbientMode;
- boolean mNotTouchable;
- Set<String> mComponentsForcingTopUi = new HashSet<>();
- Set<Object> mForceOpenTokens = new HashSet<>();
-
- /**
- * The status bar state from {@link CentralSurfaces}.
- */
- int mStatusBarState;
-
- boolean mRemoteInputActive;
- boolean mForcePluginOpen;
- boolean mDozing;
- int mScrimsVisibility;
- int mBackgroundBlurRadius;
-
- private boolean isKeyguardShowingAndNotOccluded() {
- return mKeyguardShowing && !mKeyguardOccluded;
- }
-
- @Override
- public String toString() {
- return new StringBuilder()
- .append("State{")
- .append(" mKeyguardShowing=").append(mKeyguardShowing)
- .append(", mKeyguardOccluded=").append(mKeyguardOccluded)
- .append(", mKeyguardNeedsInput=").append(mKeyguardNeedsInput)
- .append(", mPanelVisible=").append(mPanelVisible)
- .append(", mPanelExpanded=").append(mPanelExpanded)
- .append(", mNotificationShadeFocusable=").append(mNotificationShadeFocusable)
- .append(", mBouncerShowing=").append(mBouncerShowing)
- .append(", mKeyguardFadingAway=").append(mKeyguardFadingAway)
- .append(", mKeyguardGoingAway=").append(mKeyguardGoingAway)
- .append(", mQsExpanded=").append(mQsExpanded)
- .append(", mHeadsUpShowing=").append(mHeadsUpShowing)
- .append(", mLightRevealScrimOpaque=").append(mLightRevealScrimOpaque)
- .append(", mForceCollapsed=").append(mForceCollapsed)
- .append(", mForceDozeBrightness=").append(mForceDozeBrightness)
- .append(", mForceUserActivity=").append(mForceUserActivity)
- .append(", mLaunchingActivity=").append(mLaunchingActivity)
- .append(", mBackdropShowing=").append(mBackdropShowing)
- .append(", mWallpaperSupportsAmbientMode=")
- .append(mWallpaperSupportsAmbientMode)
- .append(", mNotTouchable=").append(mNotTouchable)
- .append(", mComponentsForcingTopUi=").append(mComponentsForcingTopUi)
- .append(", mForceOpenTokens=").append(mForceOpenTokens)
- .append(", mStatusBarState=").append(mStatusBarState)
- .append(", mRemoteInputActive=").append(mRemoteInputActive)
- .append(", mForcePluginOpen=").append(mForcePluginOpen)
- .append(", mDozing=").append(mDozing)
- .append(", mScrimsVisibility=").append(mScrimsVisibility)
- .append(", mBackgroundBlurRadius=").append(mBackgroundBlurRadius)
- .append('}').toString();
- }
- }
-
private final StateListener mStateListener = new StateListener() {
@Override
public void onStateChanged(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
new file mode 100644
index 000000000000..736404aa548a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
@@ -0,0 +1,214 @@
+/*
+ * 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.shade
+
+import com.android.systemui.dump.DumpsysTableLogger
+import com.android.systemui.dump.Row
+import com.android.systemui.plugins.util.RingBuffer
+import com.android.systemui.shade.NotificationShadeWindowState.Buffer
+import com.android.systemui.statusbar.StatusBarState
+
+/**
+ * Represents state of shade window, used by [NotificationShadeWindowControllerImpl].
+ * Contains nested class [Buffer] for pretty table logging in bug reports.
+ */
+class NotificationShadeWindowState(
+ @JvmField var keyguardShowing: Boolean = false,
+ @JvmField var keyguardOccluded: Boolean = false,
+ @JvmField var keyguardNeedsInput: Boolean = false,
+ @JvmField var panelVisible: Boolean = false,
+ /** shade panel is expanded (expansion fraction > 0) */
+ @JvmField var panelExpanded: Boolean = false,
+ @JvmField var notificationShadeFocusable: Boolean = false,
+ @JvmField var bouncerShowing: Boolean = false,
+ @JvmField var keyguardFadingAway: Boolean = false,
+ @JvmField var keyguardGoingAway: Boolean = false,
+ @JvmField var qsExpanded: Boolean = false,
+ @JvmField var headsUpNotificationShowing: Boolean = false,
+ @JvmField var lightRevealScrimOpaque: Boolean = false,
+ @JvmField var forceWindowCollapsed: Boolean = false,
+ @JvmField var forceDozeBrightness: Boolean = false,
+ // TODO: forceUserActivity seems to be unused, delete?
+ @JvmField var forceUserActivity: Boolean = false,
+ @JvmField var launchingActivityFromNotification: Boolean = false,
+ @JvmField var mediaBackdropShowing: Boolean = false,
+ @JvmField var wallpaperSupportsAmbientMode: Boolean = false,
+ @JvmField var windowNotTouchable: Boolean = false,
+ @JvmField var componentsForcingTopUi: MutableSet<String> = mutableSetOf(),
+ @JvmField var forceOpenTokens: MutableSet<Any> = mutableSetOf(),
+ /** one of [StatusBarState] */
+ @JvmField var statusBarState: Int = 0,
+ @JvmField var remoteInputActive: Boolean = false,
+ @JvmField var forcePluginOpen: Boolean = false,
+ @JvmField var dozing: Boolean = false,
+ @JvmField var scrimsVisibility: Int = 0,
+ @JvmField var backgroundBlurRadius: Int = 0,
+) {
+
+ fun isKeyguardShowingAndNotOccluded(): Boolean {
+ return keyguardShowing && !keyguardOccluded
+ }
+
+ /** List of [String] to be used as a [Row] with [DumpsysTableLogger]. */
+ val asStringList: List<String> by lazy {
+ listOf(
+ keyguardShowing.toString(),
+ keyguardOccluded.toString(),
+ keyguardNeedsInput.toString(),
+ panelVisible.toString(),
+ panelExpanded.toString(),
+ notificationShadeFocusable.toString(),
+ bouncerShowing.toString(),
+ keyguardFadingAway.toString(),
+ keyguardGoingAway.toString(),
+ qsExpanded.toString(),
+ headsUpNotificationShowing.toString(),
+ lightRevealScrimOpaque.toString(),
+ forceWindowCollapsed.toString(),
+ forceDozeBrightness.toString(),
+ forceUserActivity.toString(),
+ launchingActivityFromNotification.toString(),
+ mediaBackdropShowing.toString(),
+ wallpaperSupportsAmbientMode.toString(),
+ windowNotTouchable.toString(),
+ componentsForcingTopUi.toString(),
+ forceOpenTokens.toString(),
+ StatusBarState.toString(statusBarState),
+ remoteInputActive.toString(),
+ forcePluginOpen.toString(),
+ dozing.toString(),
+ scrimsVisibility.toString(),
+ backgroundBlurRadius.toString()
+ )
+ }
+
+ /**
+ * [RingBuffer] to store [NotificationShadeWindowState]. After the buffer is full, it will
+ * recycle old events.
+ */
+ class Buffer(capacity: Int) {
+
+ private val buffer = RingBuffer(capacity) { NotificationShadeWindowState() }
+
+ /** Insert a new element in the buffer. */
+ fun insert(
+ keyguardShowing: Boolean,
+ keyguardOccluded: Boolean,
+ keyguardNeedsInput: Boolean,
+ panelVisible: Boolean,
+ panelExpanded: Boolean,
+ notificationShadeFocusable: Boolean,
+ bouncerShowing: Boolean,
+ keyguardFadingAway: Boolean,
+ keyguardGoingAway: Boolean,
+ qsExpanded: Boolean,
+ headsUpShowing: Boolean,
+ lightRevealScrimOpaque: Boolean,
+ forceCollapsed: Boolean,
+ forceDozeBrightness: Boolean,
+ forceUserActivity: Boolean,
+ launchingActivity: Boolean,
+ backdropShowing: Boolean,
+ wallpaperSupportsAmbientMode: Boolean,
+ notTouchable: Boolean,
+ componentsForcingTopUi: MutableSet<String>,
+ forceOpenTokens: MutableSet<Any>,
+ statusBarState: Int,
+ remoteInputActive: Boolean,
+ forcePluginOpen: Boolean,
+ dozing: Boolean,
+ scrimsVisibility: Int,
+ backgroundBlurRadius: Int,
+ ) {
+ buffer.advance().apply {
+ this.keyguardShowing = keyguardShowing
+ this.keyguardOccluded = keyguardOccluded
+ this.keyguardNeedsInput = keyguardNeedsInput
+ this.panelVisible = panelVisible
+ this.panelExpanded = panelExpanded
+ this.notificationShadeFocusable = notificationShadeFocusable
+ this.bouncerShowing = bouncerShowing
+ this.keyguardFadingAway = keyguardFadingAway
+ this.keyguardGoingAway = keyguardGoingAway
+ this.qsExpanded = qsExpanded
+ this.headsUpNotificationShowing = headsUpShowing
+ this.lightRevealScrimOpaque = lightRevealScrimOpaque
+ this.forceWindowCollapsed = forceCollapsed
+ this.forceDozeBrightness = forceDozeBrightness
+ this.forceUserActivity = forceUserActivity
+ this.launchingActivityFromNotification = launchingActivity
+ this.mediaBackdropShowing = backdropShowing
+ this.wallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode
+ this.windowNotTouchable = notTouchable
+ this.componentsForcingTopUi.clear()
+ this.componentsForcingTopUi.addAll(componentsForcingTopUi)
+ this.forceOpenTokens.clear()
+ this.forceOpenTokens.addAll(forceOpenTokens)
+ this.statusBarState = statusBarState
+ this.remoteInputActive = remoteInputActive
+ this.forcePluginOpen = forcePluginOpen
+ this.dozing = dozing
+ this.scrimsVisibility = scrimsVisibility
+ this.backgroundBlurRadius = backgroundBlurRadius
+ }
+ }
+
+ /**
+ * Returns the content of the buffer (sorted from latest to newest).
+ *
+ * @see [NotificationShadeWindowState.asStringList]
+ */
+ fun toList(): List<Row> {
+ return buffer.asSequence().map { it.asStringList }.toList()
+ }
+ }
+
+ companion object {
+ /** Headers for dumping a table using [DumpsysTableLogger]. */
+ @JvmField
+ val TABLE_HEADERS =
+ listOf(
+ "keyguardShowing",
+ "keyguardOccluded",
+ "keyguardNeedsInput",
+ "panelVisible",
+ "panelExpanded",
+ "notificationShadeFocusable",
+ "bouncerShowing",
+ "keyguardFadingAway",
+ "keyguardGoingAway",
+ "qsExpanded",
+ "headsUpShowing",
+ "lightRevealScrimOpaque",
+ "forceCollapsed",
+ "forceDozeBrightness",
+ "forceUserActivity",
+ "launchingActivity",
+ "backdropShowing",
+ "wallpaperSupportsAmbientMode",
+ "notTouchable",
+ "componentsForcingTopUi",
+ "forceOpenTokens",
+ "statusBarState",
+ "remoteInputActive",
+ "forcePluginOpen",
+ "dozing",
+ "scrimsVisibility",
+ "backgroundBlurRadius"
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index db700650e46c..b42bdaac9cdb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -19,7 +19,6 @@ package com.android.systemui.shade
import android.hardware.display.AmbientDisplayConfiguration
import android.os.PowerManager
import android.os.SystemClock
-import android.os.UserHandle
import android.provider.Settings
import android.view.GestureDetector
import android.view.MotionEvent
@@ -29,6 +28,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
import com.android.systemui.tuner.TunerService
@@ -54,6 +54,7 @@ class PulsingGestureListener @Inject constructor(
private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
private val statusBarStateController: StatusBarStateController,
private val shadeLogger: ShadeLogger,
+ userTracker: UserTracker,
tunerService: TunerService,
dumpManager: DumpManager
) : GestureDetector.SimpleOnGestureListener(), Dumpable {
@@ -65,10 +66,10 @@ class PulsingGestureListener @Inject constructor(
when (key) {
Settings.Secure.DOZE_DOUBLE_TAP_GESTURE ->
doubleTapEnabled = ambientDisplayConfiguration.doubleTapGestureEnabled(
- UserHandle.USER_CURRENT)
+ userTracker.userId)
Settings.Secure.DOZE_TAP_SCREEN_GESTURE ->
singleTapEnabled = ambientDisplayConfiguration.tapGestureEnabled(
- UserHandle.USER_CURRENT)
+ userTracker.userId)
}
}
tunerService.addTunable(tunable,
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt b/packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt
new file mode 100644
index 000000000000..ab0d6e3a6382
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.smartspace.config
+
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.plugins.BcSmartspaceConfigPlugin
+
+class BcSmartspaceConfigProvider(private val featureFlags: FeatureFlags) :
+ BcSmartspaceConfigPlugin {
+ override val isDefaultDateWeatherDisabled: Boolean
+ get() = featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index cd423dc13c9b..17583793701c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -23,8 +23,6 @@ import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.systemui.statusbar.phone.CentralSurfacesImpl.ONLY_CORE_APPS;
-
import android.annotation.Nullable;
import android.app.ITransientNotificationCallback;
import android.app.StatusBarManager;
@@ -543,8 +541,7 @@ public class CommandQueue extends IStatusBar.Stub implements
final int disabled1 = getDisabled1(DEFAULT_DISPLAY);
final int disabled2 = getDisabled2(DEFAULT_DISPLAY);
return (disabled1 & StatusBarManager.DISABLE_EXPAND) == 0
- && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
- && !ONLY_CORE_APPS;
+ && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsModule.java
new file mode 100644
index 000000000000..a797d4a3a7b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsModule.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.BroadcastReceiver;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Module for {@link com.android.systemui.KeyboardShortcutsReceiver}.
+ */
+@Module
+public abstract class KeyboardShortcutsModule {
+
+ /**
+ *
+ */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyboardShortcutsReceiver.class)
+ public abstract BroadcastReceiver bindKeyboardShortcutsReceiver(
+ KeyboardShortcutsReceiver broadcastReceiver);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 1e7fc93cb9fa..197cf5608cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -54,7 +54,7 @@ import javax.inject.Inject
* their respective views based on the progress of the animator. Interpolation differences TBD
*/
@SysUISingleton
-class SystemStatusAnimationScheduler @Inject constructor(
+open class SystemStatusAnimationScheduler @Inject constructor(
private val coordinator: SystemEventCoordinator,
private val chipAnimationController: SystemEventChipAnimationController,
private val statusBarWindowController: StatusBarWindowController,
@@ -66,7 +66,7 @@ class SystemStatusAnimationScheduler @Inject constructor(
companion object {
private const val PROPERTY_ENABLE_IMMERSIVE_INDICATOR = "enable_immersive_indicator"
}
- private fun isImmersiveIndicatorEnabled(): Boolean {
+ public fun isImmersiveIndicatorEnabled(): Boolean {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
PROPERTY_ENABLE_IMMERSIVE_INDICATOR, true)
}
@@ -76,18 +76,22 @@ class SystemStatusAnimationScheduler @Inject constructor(
/** True if the persistent privacy dot should be active */
var hasPersistentDot = false
- private set
+ protected set
private var scheduledEvent: StatusEvent? = null
private var cancelExecutionRunnable: Runnable? = null
private val listeners = mutableSetOf<SystemStatusAnimationCallback>()
+ fun getListeners(): MutableSet<SystemStatusAnimationCallback> {
+ return listeners
+ }
+
init {
coordinator.attachScheduler(this)
dumpManager.registerDumpable(TAG, this)
}
- fun onStatusEvent(event: StatusEvent) {
+ open fun onStatusEvent(event: StatusEvent) {
// Ignore any updates until the system is up and running
if (isTooEarly() || !isImmersiveIndicatorEnabled()) {
return
@@ -139,7 +143,7 @@ class SystemStatusAnimationScheduler @Inject constructor(
}
}
- private fun isTooEarly(): Boolean {
+ public fun isTooEarly(): Boolean {
return systemClock.uptimeMillis() - Process.getStartUptimeMillis() < MIN_UPTIME
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
index 6115819b967a..5ab3d7ce9bec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
@@ -17,90 +17,25 @@
package com.android.systemui.statusbar.gesture
import android.content.Context
-import android.view.InputEvent
import android.view.MotionEvent
-import android.view.MotionEvent.ACTION_CANCEL
-import android.view.MotionEvent.ACTION_DOWN
-import android.view.MotionEvent.ACTION_MOVE
-import android.view.MotionEvent.ACTION_UP
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
-/**
- * A class to detect when a user swipes away the status bar. To be notified when the swipe away
- * gesture is detected, add a callback via [addOnGestureDetectedCallback].
- */
+/** A class to detect when a user swipes away the status bar. */
@SysUISingleton
-open class SwipeStatusBarAwayGestureHandler @Inject constructor(
+class SwipeStatusBarAwayGestureHandler
+@Inject
+constructor(
context: Context,
+ logger: SwipeUpGestureLogger,
private val statusBarWindowController: StatusBarWindowController,
- private val logger: SwipeStatusBarAwayGestureLogger
-) : GenericGestureDetector(SwipeStatusBarAwayGestureHandler::class.simpleName!!) {
-
- private var startY: Float = 0f
- private var startTime: Long = 0L
- private var monitoringCurrentTouch: Boolean = false
-
- private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
- com.android.internal.R.dimen.system_gestures_start_threshold
- )
-
- override fun onInputEvent(ev: InputEvent) {
- if (ev !is MotionEvent) {
- return
- }
-
- when (ev.actionMasked) {
- ACTION_DOWN -> {
- if (
- // Gesture starts just below the status bar
- ev.y >= statusBarWindowController.statusBarHeight
- && ev.y <= 3 * statusBarWindowController.statusBarHeight
- ) {
- logger.logGestureDetectionStarted(ev.y.toInt())
- startY = ev.y
- startTime = ev.eventTime
- monitoringCurrentTouch = true
- } else {
- monitoringCurrentTouch = false
- }
- }
- ACTION_MOVE -> {
- if (!monitoringCurrentTouch) {
- return
- }
- if (
- // Gesture is up
- ev.y < startY
- // Gesture went far enough
- && (startY - ev.y) >= swipeDistanceThreshold
- // Gesture completed quickly enough
- && (ev.eventTime - startTime) < SWIPE_TIMEOUT_MS
- ) {
- monitoringCurrentTouch = false
- logger.logGestureDetected(ev.y.toInt())
- onGestureDetected(ev)
- }
- }
- ACTION_CANCEL, ACTION_UP -> {
- if (monitoringCurrentTouch) {
- logger.logGestureDetectionEndedWithoutTriggering(ev.y.toInt())
- }
- monitoringCurrentTouch = false
- }
- }
- }
-
- override fun startGestureListening() {
- super.startGestureListening()
- logger.logInputListeningStarted()
- }
-
- override fun stopGestureListening() {
- super.stopGestureListening()
- logger.logInputListeningStopped()
+) : SwipeUpGestureHandler(context, logger, loggerTag = LOGGER_TAG) {
+ override fun startOfGestureIsWithinBounds(ev: MotionEvent): Boolean {
+ // Gesture starts just below the status bar
+ return ev.y >= statusBarWindowController.statusBarHeight &&
+ ev.y <= 3 * statusBarWindowController.statusBarHeight
}
}
-private const val SWIPE_TIMEOUT_MS: Long = 500
+private const val LOGGER_TAG = "SwipeStatusBarAway"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
new file mode 100644
index 000000000000..5ecc35ca4576
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.gesture
+
+import android.content.Context
+import android.view.InputEvent
+import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_CANCEL
+import android.view.MotionEvent.ACTION_DOWN
+import android.view.MotionEvent.ACTION_MOVE
+import android.view.MotionEvent.ACTION_UP
+import com.android.systemui.dagger.SysUISingleton
+
+/**
+ * A class to detect a generic "swipe up" gesture. To be notified when the swipe up gesture is
+ * detected, add a callback via [addOnGestureDetectedCallback].
+ */
+@SysUISingleton
+abstract class SwipeUpGestureHandler(
+ context: Context,
+ private val logger: SwipeUpGestureLogger,
+ private val loggerTag: String,
+) : GenericGestureDetector(SwipeUpGestureHandler::class.simpleName!!) {
+
+ private var startY: Float = 0f
+ private var startTime: Long = 0L
+ private var monitoringCurrentTouch: Boolean = false
+
+ private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_start_threshold
+ )
+
+ override fun onInputEvent(ev: InputEvent) {
+ if (ev !is MotionEvent) {
+ return
+ }
+
+ when (ev.actionMasked) {
+ ACTION_DOWN -> {
+ if (
+ startOfGestureIsWithinBounds(ev)
+ ) {
+ logger.logGestureDetectionStarted(loggerTag, ev.y.toInt())
+ startY = ev.y
+ startTime = ev.eventTime
+ monitoringCurrentTouch = true
+ } else {
+ monitoringCurrentTouch = false
+ }
+ }
+ ACTION_MOVE -> {
+ if (!monitoringCurrentTouch) {
+ return
+ }
+ if (
+ // Gesture is up
+ ev.y < startY &&
+ // Gesture went far enough
+ (startY - ev.y) >= swipeDistanceThreshold &&
+ // Gesture completed quickly enough
+ (ev.eventTime - startTime) < SWIPE_TIMEOUT_MS
+ ) {
+ monitoringCurrentTouch = false
+ logger.logGestureDetected(loggerTag, ev.y.toInt())
+ onGestureDetected(ev)
+ }
+ }
+ ACTION_CANCEL, ACTION_UP -> {
+ if (monitoringCurrentTouch) {
+ logger.logGestureDetectionEndedWithoutTriggering(loggerTag, ev.y.toInt())
+ }
+ monitoringCurrentTouch = false
+ }
+ }
+ }
+
+ /**
+ * Returns true if the [ACTION_DOWN] event falls within bounds for this specific swipe-up
+ * gesture.
+ *
+ * Implementations must override this method to specify what part(s) of the screen are valid
+ * locations for the swipe up gesture to start at.
+ */
+ abstract fun startOfGestureIsWithinBounds(ev: MotionEvent): Boolean
+
+ override fun startGestureListening() {
+ super.startGestureListening()
+ logger.logInputListeningStarted(loggerTag)
+ }
+
+ override fun stopGestureListening() {
+ super.stopGestureListening()
+ logger.logInputListeningStopped(loggerTag)
+ }
+}
+
+private const val SWIPE_TIMEOUT_MS: Long = 500
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
index 9bdff928c44b..9ce6b02e55d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
@@ -16,49 +16,49 @@
package com.android.systemui.statusbar.gesture
-import com.android.systemui.log.dagger.SwipeStatusBarAwayLog
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.dagger.SwipeUpLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
-/** Log messages for [SwipeStatusBarAwayGestureHandler]. */
-class SwipeStatusBarAwayGestureLogger @Inject constructor(
- @SwipeStatusBarAwayLog private val buffer: LogBuffer
+/** Log messages for [SwipeUpGestureHandler]. */
+@SysUISingleton
+class SwipeUpGestureLogger @Inject constructor(
+ @SwipeUpLog private val buffer: LogBuffer,
) {
- fun logGestureDetectionStarted(y: Int) {
+ fun logGestureDetectionStarted(tag: String, y: Int) {
buffer.log(
- TAG,
+ tag,
LogLevel.DEBUG,
{ int1 = y },
{ "Beginning gesture detection. y=$int1" }
)
}
- fun logGestureDetectionEndedWithoutTriggering(y: Int) {
+ fun logGestureDetectionEndedWithoutTriggering(tag: String, y: Int) {
buffer.log(
- TAG,
+ tag,
LogLevel.DEBUG,
{ int1 = y },
{ "Gesture finished; no swipe up gesture detected. Final y=$int1" }
)
}
- fun logGestureDetected(y: Int) {
+ fun logGestureDetected(tag: String, y: Int) {
buffer.log(
- TAG,
+ tag,
LogLevel.INFO,
{ int1 = y },
{ "Gesture detected; notifying callbacks. y=$int1" }
)
}
- fun logInputListeningStarted() {
- buffer.log(TAG, LogLevel.VERBOSE, {}, { "Input listening started "})
+ fun logInputListeningStarted(tag: String) {
+ buffer.log(tag, LogLevel.VERBOSE, {}, { "Input listening started "})
}
- fun logInputListeningStopped() {
- buffer.log(TAG, LogLevel.VERBOSE, {}, { "Input listening stopped "})
+ fun logInputListeningStopped(tag: String) {
+ buffer.log(tag, LogLevel.VERBOSE, {}, { "Input listening stopped "})
}
}
-
-private const val TAG = "SwipeStatusBarAwayGestureHandler" \ No newline at end of file
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 d6ad7d0fb8cf..284973976003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -43,6 +43,7 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.BcSmartspaceConfigPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
@@ -60,11 +61,11 @@ import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
-/**
- * Controller for managing the smartspace view on the lockscreen
- */
+/** Controller for managing the smartspace view on the lockscreen */
@SysUISingleton
-class LockscreenSmartspaceController @Inject constructor(
+class LockscreenSmartspaceController
+@Inject
+constructor(
private val context: Context,
private val featureFlags: FeatureFlags,
private val smartspaceManager: SmartspaceManager,
@@ -81,7 +82,8 @@ class LockscreenSmartspaceController @Inject constructor(
@Main private val uiExecutor: Executor,
@Background private val bgExecutor: Executor,
@Main private val handler: Handler,
- optionalPlugin: Optional<BcSmartspaceDataPlugin>
+ optionalPlugin: Optional<BcSmartspaceDataPlugin>,
+ optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
) {
companion object {
private const val TAG = "LockscreenSmartspaceController"
@@ -89,6 +91,7 @@ class LockscreenSmartspaceController @Inject constructor(
private var session: SmartspaceSession? = null
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
+ private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null)
// Smartspace can be used on multiple displays, such as when the user casts their screen
private var smartspaceViews = mutableSetOf<SmartspaceView>()
@@ -240,6 +243,7 @@ class LockscreenSmartspaceController @Inject constructor(
val ssView = plugin.getView(parent)
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
ssView.registerDataProvider(plugin)
+ ssView.registerConfigProvider(configPlugin)
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/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
index 3072c810d31b..635ed7c16140 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
@@ -25,6 +25,10 @@ class NotifPipelineFlags @Inject constructor(
val context: Context,
val featureFlags: FeatureFlags
) {
+ init {
+ featureFlags.addListener(Flags.DISABLE_FSI) { event -> event.requestNoRestart() }
+ }
+
fun isDevLoggingEnabled(): Boolean =
featureFlags.isEnabled(Flags.NOTIFICATION_PIPELINE_DEVELOPER_LOGGING)
@@ -35,13 +39,7 @@ class NotifPipelineFlags @Inject constructor(
fun fsiOnDNDUpdate(): Boolean = featureFlags.isEnabled(Flags.FSI_ON_DND_UPDATE)
- val isStabilityIndexFixEnabled: Boolean by lazy {
- featureFlags.isEnabled(Flags.STABILITY_INDEX_FIX)
- }
-
- val isSemiStableSortEnabled: Boolean by lazy {
- featureFlags.isEnabled(Flags.SEMI_STABLE_SORT)
- }
+ fun disableFsi(): Boolean = featureFlags.isEnabled(Flags.DISABLE_FSI)
val shouldFilterUnseenNotifsOnKeyguard: Boolean by lazy {
featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
index 84ab0d1190f0..b5fce4163bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
@@ -98,13 +98,11 @@ data class ListAttachState private constructor(
* This can happen if the entry is removed from a group that was broken up or if the entry was
* filtered out during any of the filtering steps.
*/
- fun detach(includingStableIndex: Boolean) {
+ fun detach() {
parent = null
section = null
promoter = null
- if (includingStableIndex) {
- stableIndex = -1
- }
+ stableIndex = -1
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 65a21a4e2190..4065b98ab0c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -965,8 +965,7 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
* filtered out during any of the filtering steps.
*/
private void annulAddition(ListEntry entry) {
- // NOTE(b/241229236): Don't clear stableIndex until we fix stability fragility
- entry.getAttachState().detach(/* includingStableIndex= */ mFlags.isSemiStableSortEnabled());
+ entry.getAttachState().detach();
}
private void assignSections() {
@@ -986,50 +985,10 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
private void sortListAndGroups() {
Trace.beginSection("ShadeListBuilder.sortListAndGroups");
- if (mFlags.isSemiStableSortEnabled()) {
- sortWithSemiStableSort();
- } else {
- sortWithLegacyStability();
- }
+ sortWithSemiStableSort();
Trace.endSection();
}
- private void sortWithLegacyStability() {
- // Sort all groups and the top level list
- for (ListEntry entry : mNotifList) {
- if (entry instanceof GroupEntry) {
- GroupEntry parent = (GroupEntry) entry;
- parent.sortChildren(mGroupChildrenComparator);
- }
- }
- mNotifList.sort(mTopLevelComparator);
- assignIndexes(mNotifList);
-
- // Check for suppressed order changes
- if (!getStabilityManager().isEveryChangeAllowed()) {
- mForceReorderable = true;
- boolean isSorted = isShadeSortedLegacy();
- mForceReorderable = false;
- if (!isSorted) {
- getStabilityManager().onEntryReorderSuppressed();
- }
- }
- }
-
- private boolean isShadeSortedLegacy() {
- if (!isSorted(mNotifList, mTopLevelComparator)) {
- return false;
- }
- for (ListEntry entry : mNotifList) {
- if (entry instanceof GroupEntry) {
- if (!isSorted(((GroupEntry) entry).getChildren(), mGroupChildrenComparator)) {
- return false;
- }
- }
- }
- return true;
- }
-
private void sortWithSemiStableSort() {
// Sort each group's children
boolean allSorted = true;
@@ -1100,29 +1059,16 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
sectionMemberIndex = 0;
currentSection = section;
}
- if (mFlags.isStabilityIndexFixEnabled()) {
- entry.getAttachState().setStableIndex(sectionMemberIndex++);
- if (entry instanceof GroupEntry) {
- final GroupEntry parent = (GroupEntry) entry;
- final NotificationEntry summary = parent.getSummary();
- if (summary != null) {
- summary.getAttachState().setStableIndex(sectionMemberIndex++);
- }
- for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setStableIndex(sectionMemberIndex++);
- }
+ entry.getAttachState().setStableIndex(sectionMemberIndex++);
+ if (entry instanceof GroupEntry) {
+ final GroupEntry parent = (GroupEntry) entry;
+ final NotificationEntry summary = parent.getSummary();
+ if (summary != null) {
+ summary.getAttachState().setStableIndex(sectionMemberIndex++);
}
- } else {
- // This old implementation uses the same index number for the group as the first
- // child, and fails to assign an index to the summary. Remove once tested.
- entry.getAttachState().setStableIndex(sectionMemberIndex);
- if (entry instanceof GroupEntry) {
- final GroupEntry parent = (GroupEntry) entry;
- for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setStableIndex(sectionMemberIndex++);
- }
+ for (NotificationEntry child : parent.getChildren()) {
+ child.getAttachState().setStableIndex(sectionMemberIndex++);
}
- sectionMemberIndex++;
}
}
}
@@ -1272,11 +1218,6 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
o2.getSectionIndex());
if (cmp != 0) return cmp;
- cmp = mFlags.isSemiStableSortEnabled() ? 0 : Integer.compare(
- getStableOrderIndex(o1),
- getStableOrderIndex(o2));
- if (cmp != 0) return cmp;
-
NotifComparator sectionComparator = getSectionComparator(o1, o2);
if (sectionComparator != null) {
cmp = sectionComparator.compare(o1, o2);
@@ -1301,12 +1242,7 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
private final Comparator<NotificationEntry> mGroupChildrenComparator = (o1, o2) -> {
- int cmp = mFlags.isSemiStableSortEnabled() ? 0 : Integer.compare(
- getStableOrderIndex(o1),
- getStableOrderIndex(o2));
- if (cmp != 0) return cmp;
-
- cmp = Integer.compare(
+ int cmp = Integer.compare(
o1.getRepresentativeEntry().getRanking().getRank(),
o2.getRepresentativeEntry().getRanking().getRank());
if (cmp != 0) return cmp;
@@ -1317,25 +1253,6 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
return cmp;
};
- /**
- * A flag that is set to true when we want to run the comparators as if all reordering is
- * allowed. This is used to check if the list is "out of order" after the sort is complete.
- */
- private boolean mForceReorderable = false;
-
- private int getStableOrderIndex(ListEntry entry) {
- if (mForceReorderable) {
- // this is used to determine if the list is correctly sorted
- return -1;
- }
- if (getStabilityManager().isEntryReorderingAllowed(entry)) {
- // let the stability manager constrain or allow reordering
- return -1;
- }
- // NOTE(b/241229236): Can't use cleared section index until we fix stability fragility
- return entry.getPreviousAttachState().getStableIndex();
- }
-
@Nullable
private Integer getStableOrderRank(ListEntry entry) {
if (getStabilityManager().isEntryReorderingAllowed(entry)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 76252d0fc5b9..e996b78133f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -114,10 +114,10 @@ constructor(
.onStart { emit(Unit) }
// for each change, lookup the new value
.map {
- secureSettings.getBoolForUser(
+ secureSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
UserHandle.USER_CURRENT,
- )
+ ) == 1
}
// perform lookups on the bg thread pool
.flowOn(bgDispatcher)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
index 7136cad22c16..bc881ce36341 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -31,6 +31,10 @@ public interface NotificationInterruptStateProvider {
*/
enum FullScreenIntentDecision {
/**
+ * Full screen intents are disabled.
+ */
+ NO_FSI_DISABLED(false),
+ /**
* No full screen intent included, so there is nothing to show.
*/
NO_FULL_SCREEN_INTENT(false),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index d9dacfd0e27c..9bcf92d63b8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -28,7 +28,6 @@ import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
@@ -40,6 +39,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -74,6 +74,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
private final NotifPipelineFlags mFlags;
private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private final UiEventLogger mUiEventLogger;
+ private final UserTracker mUserTracker;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
@@ -114,7 +115,8 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
@Main Handler mainHandler,
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker) {
mContentResolver = contentResolver;
mPowerManager = powerManager;
mDreamManager = dreamManager;
@@ -127,6 +129,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
mFlags = flags;
mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
mUiEventLogger = uiEventLogger;
+ mUserTracker = userTracker;
ContentObserver headsUpObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -236,6 +239,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
@Override
public FullScreenIntentDecision getFullScreenIntentDecision(NotificationEntry entry) {
+ if (mFlags.disableFsi()) {
+ return FullScreenIntentDecision.NO_FSI_DISABLED;
+ }
if (entry.getSbn().getNotification().fullScreenIntent == null) {
return FullScreenIntentDecision.NO_FULL_SCREEN_INTENT;
}
@@ -325,6 +331,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
final int uid = entry.getSbn().getUid();
final String packageName = entry.getSbn().getPackageName();
switch (decision) {
+ case NO_FSI_DISABLED:
+ mLogger.logNoFullscreen(entry, "Disabled");
+ return;
case NO_FULL_SCREEN_INTENT:
return;
case NO_FSI_SUPPRESSED_BY_DND:
@@ -450,7 +459,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
* @return true if the entry should ambient pulse, false otherwise
*/
private boolean shouldHeadsUpWhenDozing(NotificationEntry entry, boolean log) {
- if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
+ if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(mUserTracker.getUserId())) {
if (log) mLogger.logNoPulsingSettingDisabled(entry);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt
index ffd931c1bde2..197ae1a77198 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt
@@ -18,9 +18,12 @@
package com.android.systemui.statusbar.notification.logging
import android.stats.sysui.NotificationEnums
+import android.util.Log
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
+import com.android.systemui.dump.DumpsysTableLogger
+import com.android.systemui.dump.Row
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import java.io.PrintWriter
import javax.inject.Inject
@@ -33,6 +36,7 @@ constructor(val dumpManager: DumpManager, val notificationPipeline: NotifPipelin
fun init() {
dumpManager.registerNormalDumpable(javaClass.simpleName, this)
+ Log.i("NotificationMemory", "Registered dumpable.")
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
@@ -45,27 +49,36 @@ constructor(val dumpManager: DumpManager, val notificationPipeline: NotifPipelin
/** Renders a table of notification object usage into passed [PrintWriter]. */
private fun dumpNotificationObjects(pw: PrintWriter, memoryUse: List<NotificationMemoryUsage>) {
- pw.println("Notification Object Usage")
- pw.println("-----------")
- pw.println(
- "Package".padEnd(35) +
- "\t\tSmall\tLarge\t${"Style".padEnd(15)}\t\tStyle\tBig\tExtend.\tExtras\tCustom"
- )
- pw.println("".padEnd(35) + "\t\tIcon\tIcon\t${"".padEnd(15)}\t\tIcon\tPicture\t \t \tView")
- pw.println()
-
- memoryUse.forEach { use ->
- pw.println(
- use.packageName.padEnd(35) +
- "\t\t" +
- "${use.objectUsage.smallIcon}\t${use.objectUsage.largeIcon}\t" +
- (styleEnumToString(use.objectUsage.style).take(15) ?: "").padEnd(15) +
- "\t\t${use.objectUsage.styleIcon}\t" +
- "${use.objectUsage.bigPicture}\t${use.objectUsage.extender}\t" +
- "${use.objectUsage.extras}\t${use.objectUsage.hasCustomView}\t" +
- use.notificationKey
+ val columns =
+ listOf(
+ "Package",
+ "Small Icon",
+ "Large Icon",
+ "Style",
+ "Style Icon",
+ "Big Picture",
+ "Extender",
+ "Extras",
+ "Custom View",
+ "Key"
)
- }
+ val rows: List<Row> =
+ memoryUse.map {
+ listOf(
+ it.packageName,
+ toKb(it.objectUsage.smallIcon),
+ toKb(it.objectUsage.largeIcon),
+ styleEnumToString(it.objectUsage.style),
+ toKb(it.objectUsage.styleIcon),
+ toKb(it.objectUsage.bigPicture),
+ toKb(it.objectUsage.extender),
+ toKb(it.objectUsage.extras),
+ it.objectUsage.hasCustomView.toString(),
+ // | is a field delimiter in the output format so we need to replace
+ // it to avoid breakage.
+ it.notificationKey.replace('|', '│')
+ )
+ }
// Calculate totals for easily glanceable summary.
data class Totals(
@@ -88,18 +101,23 @@ constructor(val dumpManager: DumpManager, val notificationPipeline: NotifPipelin
t
}
- pw.println()
- pw.println("TOTALS")
- pw.println(
- "".padEnd(35) +
- "\t\t" +
- "${toKb(totals.smallIcon)}\t${toKb(totals.largeIcon)}\t" +
- "".padEnd(15) +
- "\t\t${toKb(totals.styleIcon)}\t" +
- "${toKb(totals.bigPicture)}\t${toKb(totals.extender)}\t" +
- toKb(totals.extras)
- )
- pw.println()
+ val totalsRow: List<Row> =
+ listOf(
+ listOf(
+ "TOTALS",
+ toKb(totals.smallIcon),
+ toKb(totals.largeIcon),
+ "",
+ toKb(totals.styleIcon),
+ toKb(totals.bigPicture),
+ toKb(totals.extender),
+ toKb(totals.extras),
+ "",
+ ""
+ )
+ )
+ val tableLogger = DumpsysTableLogger("Notification Object Usage", columns, rows + totalsRow)
+ tableLogger.printTableData(pw)
}
/** Renders a table of notification view usage into passed [PrintWriter] */
@@ -116,40 +134,65 @@ constructor(val dumpManager: DumpManager, val notificationPipeline: NotifPipelin
var softwareBitmapsPenalty: Int = 0,
)
+ val columns =
+ listOf(
+ "Package",
+ "View Type",
+ "Small Icon",
+ "Large Icon",
+ "Style Use",
+ "Custom View",
+ "Software Bitmaps",
+ "Key"
+ )
+ val rows =
+ memoryUse
+ .filter { it.viewUsage.isNotEmpty() }
+ .flatMap { use ->
+ use.viewUsage.map { view ->
+ listOf(
+ use.packageName,
+ view.viewType.toString(),
+ toKb(view.smallIcon),
+ toKb(view.largeIcon),
+ toKb(view.style),
+ toKb(view.customViews),
+ toKb(view.softwareBitmapsPenalty),
+ // | is a field delimiter in the output format so we need to replace
+ // it to avoid breakage.
+ use.notificationKey.replace('|', '│')
+ )
+ }
+ }
+
val totals = Totals()
- pw.println("Notification View Usage")
- pw.println("-----------")
- pw.println("View Type".padEnd(24) + "\tSmall\tLarge\tStyle\tCustom\tSoftware")
- pw.println("".padEnd(24) + "\tIcon\tIcon\tUse\tView\tBitmaps")
- pw.println()
memoryUse
.filter { it.viewUsage.isNotEmpty() }
- .forEach { use ->
- pw.println(use.packageName + " " + use.notificationKey)
- use.viewUsage.forEach { view ->
- pw.println(
- " ${view.viewType.toString().padEnd(24)}\t${view.smallIcon}" +
- "\t${view.largeIcon}\t${view.style}" +
- "\t${view.customViews}\t${view.softwareBitmapsPenalty}"
- )
-
- if (view.viewType == ViewType.TOTAL) {
- totals.smallIcon += view.smallIcon
- totals.largeIcon += view.largeIcon
- totals.style += view.style
- totals.customViews += view.customViews
- totals.softwareBitmapsPenalty += view.softwareBitmapsPenalty
- }
- }
+ .map { it.viewUsage.firstOrNull { view -> view.viewType == ViewType.TOTAL } }
+ .filterNotNull()
+ .forEach { view ->
+ totals.smallIcon += view.smallIcon
+ totals.largeIcon += view.largeIcon
+ totals.style += view.style
+ totals.customViews += view.customViews
+ totals.softwareBitmapsPenalty += view.softwareBitmapsPenalty
}
- pw.println()
- pw.println("TOTALS")
- pw.println(
- " ${"".padEnd(24)}\t${toKb(totals.smallIcon)}" +
- "\t${toKb(totals.largeIcon)}\t${toKb(totals.style)}" +
- "\t${toKb(totals.customViews)}\t${toKb(totals.softwareBitmapsPenalty)}"
- )
- pw.println()
+
+ val totalsRow: List<Row> =
+ listOf(
+ listOf(
+ "TOTALS",
+ "",
+ toKb(totals.smallIcon),
+ toKb(totals.largeIcon),
+ toKb(totals.style),
+ toKb(totals.customViews),
+ toKb(totals.softwareBitmapsPenalty),
+ ""
+ )
+ )
+ val tableLogger = DumpsysTableLogger("Notification View Usage", columns, rows + totalsRow)
+ tableLogger.printTableData(pw)
}
private fun styleEnumToString(styleEnum: Int): String =
@@ -168,6 +211,10 @@ constructor(val dumpManager: DumpManager, val notificationPipeline: NotifPipelin
}
private fun toKb(bytes: Int): String {
- return (bytes / 1024).toString() + " KB"
+ if (bytes == 0) {
+ return "--"
+ }
+
+ return "%.2f KB".format(bytes / 1024f)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index fbe88dff07f1..7addc8fe7a15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -24,6 +24,7 @@ import android.graphics.Canvas;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.MathUtils;
+import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
@@ -492,12 +493,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (animationListener != null) {
mAppearAnimator.addListener(animationListener);
}
- if (delay > 0) {
- // we need to apply the initial state already to avoid drawn frames in the wrong state
- updateAppearAnimationAlpha();
- updateAppearRect();
- mAppearAnimator.setStartDelay(delay);
- }
+ // we need to apply the initial state already to avoid drawn frames in the wrong state
+ updateAppearAnimationAlpha();
+ updateAppearRect();
mAppearAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mWasCancelled;
@@ -528,7 +526,20 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mWasCancelled = true;
}
});
- mAppearAnimator.start();
+
+ // Cache the original animator so we can check if the animation should be started in the
+ // Choreographer callback. It's possible that the original animator (mAppearAnimator) is
+ // replaced with a new value before the callback is called.
+ ValueAnimator cachedAnimator = mAppearAnimator;
+ // Even when delay=0, starting the animation on the next frame is necessary to avoid jank.
+ // Not doing so will increase the chances our Animator will be forced to skip a value of
+ // the animation's progression, causing stutter.
+ Choreographer.getInstance().postFrameCallbackDelayed(
+ frameTimeNanos -> {
+ if (mAppearAnimator == cachedAnimator) {
+ mAppearAnimator.start();
+ }
+ }, delay);
}
private int getCujType(boolean isAppearing) {
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 9f50aef6de11..9275e2b603c3 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
@@ -79,6 +79,8 @@ import com.android.internal.widget.CallLayout;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -177,6 +179,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private Optional<BubblesManager> mBubblesManagerOptional;
private MetricsLogger mMetricsLogger;
+ private FeatureFlags mFeatureFlags;
private int mIconTransformContentShift;
private int mMaxHeadsUpHeightBeforeN;
private int mMaxHeadsUpHeightBeforeP;
@@ -277,7 +280,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mChildIsExpanding;
private boolean mJustClicked;
- private boolean mIconAnimationRunning;
+ private boolean mAnimationRunning;
private boolean mShowNoBackground;
private ExpandableNotificationRow mNotificationParent;
private OnExpandClickListener mOnExpandClickListener;
@@ -451,10 +454,26 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mPublicLayout;
}
- public void setIconAnimationRunning(boolean running) {
- for (NotificationContentView l : mLayouts) {
- setIconAnimationRunning(running, l);
+ /**
+ * Sets animations running in the layouts of this row, including public, private, and children.
+ * @param running whether the animations should be started running or stopped.
+ */
+ public void setAnimationRunning(boolean running) {
+ // Sets animations running in the private/public layouts.
+ if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ANIMATE_BIG_PICTURE)) {
+ for (NotificationContentView l : mLayouts) {
+ if (l != null) {
+ l.setContentAnimationRunning(running);
+ setIconAnimationRunning(running, l);
+ }
+ }
+ } else {
+ for (NotificationContentView l : mLayouts) {
+ setIconAnimationRunning(running, l);
+ }
}
+ // For groups summaries with children, we want to set the children containers
+ // animating as well.
if (mIsSummaryWithChildren) {
NotificationViewWrapper viewWrapper = mChildrenContainer.getNotificationViewWrapper();
if (viewWrapper != null) {
@@ -468,12 +487,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mChildrenContainer.getAttachedChildren();
for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow child = notificationChildren.get(i);
- child.setIconAnimationRunning(running);
+ child.setAnimationRunning(running);
}
}
- mIconAnimationRunning = running;
+ mAnimationRunning = running;
}
+ /**
+ * Starts or stops animations of the icons in all potential content views (regardless of
+ * whether they're contracted, expanded, etc).
+ *
+ * @param running whether to start or stop the icon's animation.
+ */
private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
if (layout != null) {
View contractedChild = layout.getContractedChild();
@@ -485,16 +510,29 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
+ /**
+ * Starts or stops animations of the icon in the provided view's icon and right icon.
+ *
+ * @param running whether to start or stop the icon's animation.
+ * @param child the view with the icon to start or stop.
+ */
private void setIconAnimationRunningForChild(boolean running, View child) {
if (child != null) {
ImageView icon = child.findViewById(com.android.internal.R.id.icon);
- setIconRunning(icon, running);
+ setImageViewAnimationRunning(icon, running);
ImageView rightIcon = child.findViewById(com.android.internal.R.id.right_icon);
- setIconRunning(rightIcon, running);
+ setImageViewAnimationRunning(rightIcon, running);
}
}
- private void setIconRunning(ImageView imageView, boolean running) {
+ /**
+ * Starts or stops the animation of a provided image view if it's an AnimationDrawable or an
+ * AnimatedVectorDrawable.
+ *
+ * @param imageView the image view on which to start/stop animation.
+ * @param running whether to start or stop the view's animation.
+ */
+ private void setImageViewAnimationRunning(ImageView imageView, boolean running) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof AnimationDrawable) {
@@ -561,8 +599,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mChildrenContainer.recreateNotificationHeader(mExpandClickListener, isConversation());
mChildrenContainer.onNotificationUpdated();
}
- if (mIconAnimationRunning) {
- setIconAnimationRunning(true);
+ if (mAnimationRunning) {
+ setAnimationRunning(true);
}
if (mLastChronometerRunning) {
setChronometerRunning(true);
@@ -1038,7 +1076,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
notifyHeightChanged(false /* needsAnimation */);
}
if (pinned) {
- setIconAnimationRunning(true);
+ setAnimationRunning(true);
mExpandedWhenPinned = false;
} else if (mExpandedWhenPinned) {
setUserExpanded(true);
@@ -1627,6 +1665,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
);
}
+ /**
+ * Constructs an ExpandableNotificationRow.
+ * @param context context passed to image resolver
+ * @param attrs attributes used to initialize parent view
+ */
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
mImageResolver = new NotificationInlineImageResolver(context,
@@ -1662,7 +1705,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
NotificationGutsManager gutsManager,
MetricsLogger metricsLogger,
SmartReplyConstants smartReplyConstants,
- SmartReplyController smartReplyController) {
+ SmartReplyController smartReplyController,
+ FeatureFlags featureFlags) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1697,6 +1741,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mBubblesManagerOptional = bubblesManagerOptional;
mNotificationGutsManager = gutsManager;
mMetricsLogger = metricsLogger;
+ mFeatureFlags = featureFlags;
}
private void initDimens() {
@@ -3588,11 +3633,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@VisibleForTesting
protected void setPrivateLayout(NotificationContentView privateLayout) {
mPrivateLayout = privateLayout;
+ mLayouts = new NotificationContentView[]{mPrivateLayout, mPublicLayout};
}
@VisibleForTesting
protected void setPublicLayout(NotificationContentView publicLayout) {
mPublicLayout = publicLayout;
+ mLayouts = new NotificationContentView[]{mPrivateLayout, mPublicLayout};
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index d1138608805b..bb92dfcdfcb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -219,7 +219,8 @@ public class ExpandableNotificationRowController implements NotifViewController
mNotificationGutsManager,
mMetricsLogger,
mSmartReplyConstants,
- mSmartReplyController
+ mSmartReplyController,
+ mFeatureFlags
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 49dc6550a51f..21f4cb566e28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,15 +16,22 @@
package com.android.systemui.statusbar.notification.row;
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.IndentingPrintWriter;
import android.view.View;
+import android.widget.TextView;
import androidx.annotation.NonNull;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -41,6 +48,11 @@ public class FooterView extends StackScrollerDecorView {
private String mManageNotificationText;
private String mManageNotificationHistoryText;
+ // Footer label
+ private TextView mSeenNotifsFooterTextView;
+ private @StringRes int mSeenNotifsFilteredText;
+ private int mUnlockIconSize;
+
public FooterView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -73,10 +85,41 @@ public class FooterView extends StackScrollerDecorView {
super.onFinishInflate();
mClearAllButton = (FooterViewButton) findSecondaryView();
mManageButton = findViewById(R.id.manage_text);
+ mSeenNotifsFooterTextView = findViewById(R.id.unlock_prompt_footer);
updateResources();
updateText();
}
+ public void setFooterLabelTextAndIcon(@StringRes int text, @DrawableRes int icon) {
+ mSeenNotifsFilteredText = text;
+ if (mSeenNotifsFilteredText != 0) {
+ mSeenNotifsFooterTextView.setText(mSeenNotifsFilteredText);
+ } else {
+ mSeenNotifsFooterTextView.setText(null);
+ }
+ Drawable drawable;
+ if (icon == 0) {
+ drawable = null;
+ } else {
+ drawable = getResources().getDrawable(icon);
+ drawable.setBounds(0, 0, mUnlockIconSize, mUnlockIconSize);
+ }
+ mSeenNotifsFooterTextView.setCompoundDrawablesRelative(drawable, null, null, null);
+ updateFooterVisibilityMode();
+ }
+
+ private void updateFooterVisibilityMode() {
+ if (mSeenNotifsFilteredText != 0) {
+ mManageButton.setVisibility(View.GONE);
+ mClearAllButton.setVisibility(View.GONE);
+ mSeenNotifsFooterTextView.setVisibility(View.VISIBLE);
+ } else {
+ mManageButton.setVisibility(View.VISIBLE);
+ mClearAllButton.setVisibility(View.VISIBLE);
+ mSeenNotifsFooterTextView.setVisibility(View.GONE);
+ }
+ }
+
public void setManageButtonClickListener(OnClickListener listener) {
mManageButton.setOnClickListener(listener);
}
@@ -135,12 +178,19 @@ public class FooterView extends StackScrollerDecorView {
mClearAllButton.setTextColor(textColor);
mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
mManageButton.setTextColor(textColor);
+ final @ColorInt int labelTextColor =
+ Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
+ mSeenNotifsFooterTextView.setTextColor(labelTextColor);
+ mSeenNotifsFooterTextView.setCompoundDrawableTintList(
+ ColorStateList.valueOf(labelTextColor));
}
private void updateResources() {
mManageNotificationText = getContext().getString(R.string.manage_notifications_text);
mManageNotificationHistoryText = getContext()
.getString(R.string.manage_notifications_history_text);
+ mUnlockIconSize = getResources()
+ .getDimensionPixelSize(R.dimen.notifications_unseen_footer_icon_size);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index e46bf522acff..4a023c41388e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -184,6 +184,8 @@ public class NotificationContentView extends FrameLayout implements Notification
private boolean mRemoteInputVisible;
private int mUnrestrictedContentHeight;
+ private boolean mContentAnimating;
+
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
mHybridGroupManager = new HybridGroupManager(getContext());
@@ -2129,8 +2131,49 @@ public class NotificationContentView extends FrameLayout implements Notification
return false;
}
+ /**
+ * Starts and stops animations in the underlying views.
+ * Avoids restarting the animations by checking whether they're already running first.
+ * Return value is used for testing.
+ *
+ * @param running whether to start animations running, or stop them.
+ * @return true if the state of animations changed.
+ */
+ public boolean setContentAnimationRunning(boolean running) {
+ boolean stateChangeRequired = (running != mContentAnimating);
+ if (stateChangeRequired) {
+ // Starts or stops the animations in the potential views.
+ if (mContractedWrapper != null) {
+ mContractedWrapper.setAnimationsRunning(running);
+ }
+ if (mExpandedWrapper != null) {
+ mExpandedWrapper.setAnimationsRunning(running);
+ }
+ if (mHeadsUpWrapper != null) {
+ mHeadsUpWrapper.setAnimationsRunning(running);
+ }
+ // Updates the state tracker.
+ mContentAnimating = running;
+ return true;
+ }
+ return false;
+ }
+
private static class RemoteInputViewData {
@Nullable RemoteInputView mView;
@Nullable RemoteInputViewController mController;
}
+
+ @VisibleForTesting
+ protected void setContractedWrapper(NotificationViewWrapper contractedWrapper) {
+ mContractedWrapper = contractedWrapper;
+ }
+ @VisibleForTesting
+ protected void setExpandedWrapper(NotificationViewWrapper expandedWrapper) {
+ mExpandedWrapper = expandedWrapper;
+ }
+ @VisibleForTesting
+ protected void setHeadsUpWrapper(NotificationViewWrapper headsUpWrapper) {
+ mHeadsUpWrapper = headsUpWrapper;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
index 8732696dc7a1..175ba15eebae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
@@ -18,11 +18,15 @@ package com.android.systemui.statusbar.notification.row.wrapper;
import android.app.Notification;
import android.content.Context;
+import android.graphics.drawable.AnimatedImageDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.view.View;
+import com.android.internal.R;
+import com.android.internal.widget.BigPictureNotificationImageView;
import com.android.systemui.statusbar.notification.ImageTransformState;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -31,6 +35,8 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
*/
public class NotificationBigPictureTemplateViewWrapper extends NotificationTemplateViewWrapper {
+ private BigPictureNotificationImageView mImageView;
+
protected NotificationBigPictureTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
@@ -39,9 +45,14 @@ public class NotificationBigPictureTemplateViewWrapper extends NotificationTempl
@Override
public void onContentUpdated(ExpandableNotificationRow row) {
super.onContentUpdated(row);
+ resolveViews();
updateImageTag(row.getEntry().getSbn());
}
+ private void resolveViews() {
+ mImageView = mView.findViewById(R.id.big_picture);
+ }
+
private void updateImageTag(StatusBarNotification sbn) {
final Bundle extras = sbn.getNotification().extras;
Icon bigLargeIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG, Icon.class);
@@ -54,4 +65,25 @@ public class NotificationBigPictureTemplateViewWrapper extends NotificationTempl
mRightIcon.setTag(ImageTransformState.ICON_TAG, getLargeIcon(sbn.getNotification()));
}
}
+
+ /**
+ * Starts or stops the animations in any drawables contained in this BigPicture Notification.
+ *
+ * @param running Whether the animations should be set to run.
+ */
+ @Override
+ public void setAnimationsRunning(boolean running) {
+ if (mImageView == null) {
+ return;
+ }
+ Drawable d = mImageView.getDrawable();
+ if (d instanceof AnimatedImageDrawable) {
+ AnimatedImageDrawable animatedImageDrawable = (AnimatedImageDrawable) d;
+ if (running) {
+ animatedImageDrawable.start();
+ } else {
+ animatedImageDrawable.stop();
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index e136055b80b3..10753f215103 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -17,16 +17,20 @@
package com.android.systemui.statusbar.notification.row.wrapper
import android.content.Context
+import android.graphics.drawable.AnimatedImageDrawable
import android.view.View
import android.view.ViewGroup
import com.android.internal.widget.CachingIconView
import com.android.internal.widget.ConversationLayout
+import com.android.internal.widget.MessagingGroup
+import com.android.internal.widget.MessagingImageMessage
import com.android.internal.widget.MessagingLinearLayout
import com.android.systemui.R
import com.android.systemui.statusbar.notification.NotificationFadeAware
import com.android.systemui.statusbar.notification.NotificationUtils
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.wrapper.NotificationMessagingTemplateViewWrapper.setCustomImageMessageTransform
+import com.android.systemui.util.children
/**
* Wraps a notification containing a conversation template
@@ -49,6 +53,7 @@ class NotificationConversationTemplateViewWrapper constructor(
private lateinit var expandBtn: View
private lateinit var expandBtnContainer: View
private lateinit var imageMessageContainer: ViewGroup
+ private lateinit var messageContainers: ArrayList<MessagingGroup>
private lateinit var messagingLinearLayout: MessagingLinearLayout
private lateinit var conversationTitleView: View
private lateinit var importanceRing: View
@@ -60,6 +65,7 @@ class NotificationConversationTemplateViewWrapper constructor(
private fun resolveViews() {
messagingLinearLayout = conversationLayout.messagingLinearLayout
imageMessageContainer = conversationLayout.imageMessageContainer
+ messageContainers = conversationLayout.messagingGroups
with(conversationLayout) {
conversationIconContainer =
requireViewById(com.android.internal.R.id.conversation_icon_container)
@@ -146,4 +152,26 @@ class NotificationConversationTemplateViewWrapper constructor(
NotificationFadeAware.setLayerTypeForFaded(expandBtn, faded)
NotificationFadeAware.setLayerTypeForFaded(conversationIconContainer, faded)
}
+
+ // Starts or stops the animations in any drawables contained in this Conversation Notification.
+ override fun setAnimationsRunning(running: Boolean) {
+ // We apply to both the child message containers in a conversation group,
+ // and the top level image message container.
+ val containers = messageContainers.asSequence().map { it.messageContainer } +
+ sequenceOf(imageMessageContainer)
+ val drawables =
+ containers
+ .flatMap { it.children }
+ .mapNotNull { child ->
+ (child as? MessagingImageMessage)?.let { imageMessage ->
+ imageMessage.drawable as? AnimatedImageDrawable
+ }
+ }
+ drawables.toSet().forEach {
+ when {
+ running -> it.start()
+ !running -> it.stop()
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
index c587ce05b13f..4592fde69a93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
@@ -17,9 +17,13 @@
package com.android.systemui.statusbar.notification.row.wrapper;
import android.content.Context;
+import android.graphics.drawable.AnimatedImageDrawable;
+import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.widget.MessagingGroup;
+import com.android.internal.widget.MessagingImageMessage;
import com.android.internal.widget.MessagingLayout;
import com.android.internal.widget.MessagingLinearLayout;
import com.android.systemui.R;
@@ -127,4 +131,40 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
}
return super.getMinLayoutHeight();
}
+
+ /**
+ * Starts or stops the animations in any drawables contained in this Messaging Notification.
+ *
+ * @param running Whether the animations should be set to run.
+ */
+ @Override
+ public void setAnimationsRunning(boolean running) {
+ if (mMessagingLayout == null) {
+ return;
+ }
+
+ for (MessagingGroup group : mMessagingLayout.getMessagingGroups()) {
+ for (int i = 0; i < group.getMessageContainer().getChildCount(); i++) {
+ View view = group.getMessageContainer().getChildAt(i);
+ // We only need to set animations in MessagingImageMessages.
+ if (!(view instanceof MessagingImageMessage)) {
+ continue;
+ }
+ MessagingImageMessage imageMessage =
+ (com.android.internal.widget.MessagingImageMessage) view;
+
+ // If the drawable isn't an AnimatedImageDrawable, we can't set it to animate.
+ Drawable d = imageMessage.getDrawable();
+ if (!(d instanceof AnimatedImageDrawable)) {
+ continue;
+ }
+ AnimatedImageDrawable animatedImageDrawable = (AnimatedImageDrawable) d;
+ if (running) {
+ animatedImageDrawable.start();
+ } else {
+ animatedImageDrawable.stop();
+ }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 1c22f0933236..ff5b9cbf3c23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -403,4 +403,12 @@ public abstract class NotificationViewWrapper implements TransformableView {
NotificationFadeAware.setLayerTypeForFaded(getIcon(), faded);
NotificationFadeAware.setLayerTypeForFaded(getExpandButton(), faded);
}
+
+ /**
+ * Starts or stops the animations in any drawables contained in this Notification.
+ *
+ * @param running Whether the animations should be set to run.
+ */
+ public void setAnimationsRunning(boolean running) {
+ }
}
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 356ddfa2d482..aab36da66bdf 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
@@ -538,6 +538,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
private final ScreenOffAnimationController mScreenOffAnimationController;
private boolean mShouldUseSplitNotificationShade;
+ private boolean mHasFilteredOutSeenNotifications;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
new ExpandableView.OnHeightChangedListener() {
@@ -684,6 +685,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateFooter();
}
+ void setHasFilteredOutSeenNotifications(boolean hasFilteredOutSeenNotifications) {
+ mHasFilteredOutSeenNotifications = hasFilteredOutSeenNotifications;
+ }
+
@VisibleForTesting
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
@@ -3132,7 +3137,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private void updateAnimationState(boolean running, View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- row.setIconAnimationRunning(running);
+ row.setAnimationRunning(running);
}
}
@@ -4612,13 +4617,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void updateEmptyShadeView(
- boolean visible, boolean areNotificationsHiddenInShade, boolean areSeenNotifsFiltered) {
+ void updateEmptyShadeView(boolean visible, boolean areNotificationsHiddenInShade) {
mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
if (areNotificationsHiddenInShade) {
updateEmptyShadeView(R.string.dnd_suppressing_shade_text, 0, 0);
- } else if (areSeenNotifsFiltered) {
+ } else if (mHasFilteredOutSeenNotifications) {
updateEmptyShadeView(
R.string.no_unseen_notif_text,
R.string.unlock_to_see_notif_text,
@@ -4657,13 +4661,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooterView(boolean visible, boolean showDismissView, boolean showHistory) {
- if (mFooterView == null) {
+ if (mFooterView == null || mNotificationStackSizeCalculator == null) {
return;
}
boolean animate = mIsExpanded && mAnimationsEnabled;
mFooterView.setVisible(visible, animate);
mFooterView.setSecondaryVisible(showDismissView, animate);
mFooterView.showHistory(showHistory);
+ if (mHasFilteredOutSeenNotifications) {
+ mFooterView.setFooterLabelTextAndIcon(
+ R.string.unlock_to_see_notif_text,
+ R.drawable.ic_friction_lock_closed);
+ } else {
+ mFooterView.setFooterLabelTextAndIcon(0, 0);
+ }
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
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 58919489496d..42d122d6f9ac 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
@@ -120,6 +120,7 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Compile;
+import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
import java.util.List;
@@ -189,6 +190,7 @@ public class NotificationStackScrollLayoutController {
private final FeatureFlags mFeatureFlags;
private final boolean mUseRoundnessSourceTypes;
private final NotificationTargetsHelper mNotificationTargetsHelper;
+ private final SecureSettings mSecureSettings;
private View mLongPressedView;
@@ -667,7 +669,8 @@ public class NotificationStackScrollLayoutController {
NotificationStackScrollLogger logger,
NotificationStackSizeCalculator notificationStackSizeCalculator,
FeatureFlags featureFlags,
- NotificationTargetsHelper notificationTargetsHelper) {
+ NotificationTargetsHelper notificationTargetsHelper,
+ SecureSettings secureSettings) {
mStackStateLogger = stackLogger;
mLogger = logger;
mAllowLongPress = allowLongPress;
@@ -709,6 +712,7 @@ public class NotificationStackScrollLayoutController {
mFeatureFlags = featureFlags;
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
mNotificationTargetsHelper = notificationTargetsHelper;
+ mSecureSettings = secureSettings;
updateResources();
}
@@ -1015,8 +1019,7 @@ public class NotificationStackScrollLayoutController {
Log.wtf(TAG, "isHistoryEnabled failed to initialize its value");
return false;
}
- mHistoryEnabled = historyEnabled = Settings.Secure.getIntForUser(
- mView.getContext().getContentResolver(),
+ mHistoryEnabled = historyEnabled = mSecureSettings.getIntForUser(
Settings.Secure.NOTIFICATION_HISTORY_ENABLED,
0,
UserHandle.USER_CURRENT) == 1;
@@ -1242,11 +1245,7 @@ public class NotificationStackScrollLayoutController {
// For more details, see: b/228790482
&& !isInTransitionToKeyguard();
- mView.updateEmptyShadeView(
- shouldShow,
- mZenModeController.areNotificationsHiddenInShade(),
- mNotifPipelineFlags.getShouldFilterUnseenNotifsOnKeyguard()
- && mSeenNotificationsProvider.getHasFilteredOutSeenNotifications());
+ mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade());
Trace.endSection();
}
@@ -1942,6 +1941,9 @@ public class NotificationStackScrollLayoutController {
@Override
public void setNotifStats(@NonNull NotifStats notifStats) {
mNotifStats = notifStats;
+ mView.setHasFilteredOutSeenNotifications(
+ mNotifPipelineFlags.getShouldFilterUnseenNotifsOnKeyguard()
+ && mSeenNotificationsProvider.getHasFilteredOutSeenNotifications());
updateFooter();
updateShowEmptyShadeView();
}
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 2dad8e053ee1..ccde3c21798e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -31,7 +31,6 @@ import android.content.res.Resources;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -55,6 +54,7 @@ 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.QSPanelController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeController;
@@ -99,6 +99,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
private final Optional<Vibrator> mVibratorOptional;
private final DisableFlagsLogger mDisableFlagsLogger;
private final int mDisplayId;
+ private final UserTracker mUserTracker;
private final boolean mVibrateOnOpening;
private final VibrationEffect mCameraLaunchGestureVibrationEffect;
private final SystemBarAttributesListener mSystemBarAttributesListener;
@@ -133,7 +134,8 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
DisableFlagsLogger disableFlagsLogger,
@DisplayId int displayId,
SystemBarAttributesListener systemBarAttributesListener,
- Lazy<CameraLauncher> cameraLauncherLazy) {
+ Lazy<CameraLauncher> cameraLauncherLazy,
+ UserTracker userTracker) {
mCentralSurfaces = centralSurfaces;
mContext = context;
mShadeController = shadeController;
@@ -157,6 +159,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
mDisableFlagsLogger = disableFlagsLogger;
mDisplayId = displayId;
mCameraLauncherLazy = cameraLauncherLazy;
+ mUserTracker = userTracker;
mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation);
mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
@@ -215,7 +218,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
return;
}
- mNotificationPanelViewController.expandWithoutQs();
+ mNotificationPanelViewController.expandShadeToNotifications();
}
@Override
@@ -375,7 +378,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */, UserHandle.CURRENT);
+ null /* animationController */, mUserTracker.getUserHandle());
} else {
if (!mCentralSurfaces.isDeviceInteractive()) {
// Avoid flickering of the scrim when we instant launch the camera and the bouncer
@@ -432,7 +435,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */, UserHandle.CURRENT);
+ null /* animationController */, mUserTracker.getUserHandle());
return;
}
@@ -447,7 +450,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.reset(true /* hide */);
}
- mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
+ mContext.startActivityAsUser(emergencyIntent, mUserTracker.getUserHandle());
return;
}
// We need to defer the emergency action launch until the screen comes on, since otherwise
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 8110b4747b63..dd75d356a60b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -64,7 +64,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
@@ -180,6 +179,7 @@ import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.scrim.ScrimView;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.NotificationPanelViewController;
@@ -292,24 +292,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
- /**
- * If true, the system is in the half-boot-to-decryption-screen state.
- * Prudently disable QS and notifications.
- */
- public static final boolean ONLY_CORE_APPS;
-
- static {
- boolean onlyCoreApps;
- try {
- IPackageManager packageManager =
- IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- onlyCoreApps = packageManager != null && packageManager.isOnlyCoreApps();
- } catch (RemoteException e) {
- onlyCoreApps = false;
- }
- ONLY_CORE_APPS = onlyCoreApps;
- }
-
private final Context mContext;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final DeviceStateManager mDeviceStateManager;
@@ -524,6 +506,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final MessageRouter mMessageRouter;
private final WallpaperManager mWallpaperManager;
+ private final UserTracker mUserTracker;
private CentralSurfacesComponent mCentralSurfacesComponent;
@@ -767,7 +750,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
IDreamManager dreamManager,
Lazy<CameraLauncher> cameraLauncherLazy,
Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy,
- AlternateBouncerInteractor alternateBouncerInteractor
+ AlternateBouncerInteractor alternateBouncerInteractor,
+ UserTracker userTracker
) {
mContext = context;
mNotificationsController = notificationsController;
@@ -847,6 +831,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mJankMonitor = jankMonitor;
mCameraLauncherLazy = cameraLauncherLazy;
mAlternateBouncerInteractor = alternateBouncerInteractor;
+ mUserTracker = userTracker;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
@@ -884,6 +869,11 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
wiredChargingRippleController.registerCallbacks();
mLightRevealScrimViewModelLazy = lightRevealScrimViewModelLazy;
+
+ // Based on teamfood flag, turn predictive back dispatch on at runtime.
+ if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI)) {
+ mContext.getApplicationInfo().setEnableOnBackInvokedCallback(true);
+ }
}
@Override
@@ -998,11 +988,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy.init();
- // Based on teamfood flag, turn predictive back dispatch on at runtime.
- if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI)) {
- mContext.getApplicationInfo().setEnableOnBackInvokedCallback(true);
- }
-
mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onUnlockedChanged() {
@@ -1414,6 +1399,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// Things that mean we're not swiping to dismiss the keyguard, and should ignore this
// expansion:
// - Keyguard isn't even visible.
+ // - We're swiping on the bouncer, not the lockscreen.
// - Keyguard is occluded. Expansion changes here are the shade being expanded over the
// occluding activity.
// - Keyguard is visible, but can't be dismissed (swiping up will show PIN/password prompt).
@@ -1423,6 +1409,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// - QS is expanded and we're swiping - swiping up now will hide QS, not dismiss the
// keyguard.
if (!isKeyguardShowing()
+ || mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()
|| isOccluded()
|| !mKeyguardStateController.canDismissLockScreen()
|| mKeyguardViewMediator.isAnySimPinSecure()
@@ -1702,8 +1689,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
|| !mUserSwitcherController.isSimpleUserSwitcher())
&& !isShadeDisabled()
&& ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
- && !mDozing
- && !ONLY_CORE_APPS;
+ && !mDozing;
mNotificationPanelViewController.setQsExpansionEnabledPolicy(expandEnabled);
Log.d(TAG, "updateQsExpansionEnabled - QS Expand enabled: " + expandEnabled);
}
@@ -4172,7 +4158,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
Log.wtf(TAG, "WallpaperManager not supported");
return;
}
- WallpaperInfo info = mWallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
+ WallpaperInfo info = mWallpaperManager.getWallpaperInfo(mUserTracker.getUserId());
mWallpaperController.onWallpaperInfoUpdated(info);
final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
@@ -4396,6 +4382,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
return new UserHandle(UserHandle.myUserId());
}
}
- return UserHandle.CURRENT;
+ return mUserTracker.getUserHandle();
}
}
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 0446cefb10dc..c248a5091765 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -45,6 +45,7 @@ import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -84,6 +85,7 @@ public class DozeParameters implements
private final ScreenOffAnimationController mScreenOffAnimationController;
private final FoldAodAnimationController mFoldAodAnimationController;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ private final UserTracker mUserTracker;
private final Set<Callback> mCallbacks = new HashSet<>();
@@ -128,7 +130,8 @@ public class DozeParameters implements
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ UserTracker userTracker) {
mResources = resources;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mAlwaysOnPolicy = alwaysOnDisplayPolicy;
@@ -140,6 +143,7 @@ public class DozeParameters implements
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
mScreenOffAnimationController = screenOffAnimationController;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+ mUserTracker = userTracker;
keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
tunerService.addTunable(
@@ -169,7 +173,7 @@ public class DozeParameters implements
private void updateQuickPickupEnabled() {
mIsQuickPickupEnabled =
- mAmbientDisplayConfiguration.quickPickupSensorEnabled(UserHandle.USER_CURRENT);
+ mAmbientDisplayConfiguration.quickPickupSensorEnabled(mUserTracker.getUserId());
}
public boolean getDisplayStateSupported() {
@@ -418,7 +422,7 @@ public class DozeParameters implements
@Override
public void onTuningChanged(String key, String newValue) {
- mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
+ mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(mUserTracker.getUserId());
if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) {
updateControlScreenOff();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index f08de85ec02c..d31875935dd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -46,6 +46,8 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.KeyguardResetCallback;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ListenerSet;
@@ -658,56 +660,6 @@ public class KeyguardBouncer {
mExpansionCallbacks.remove(callback);
}
- /**
- * Callback updated when the primary bouncer's show and hide states change.
- */
- public interface PrimaryBouncerExpansionCallback {
- /**
- * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_VISIBLE}.
- * This is NOT called each time the bouncer is shown, but rather only when the fully
- * shown amount has changed based on the panel expansion. The bouncer's visibility
- * can still change when the expansion amount hasn't changed.
- * See {@link KeyguardBouncer#isShowing()} for the checks for the bouncer showing state.
- */
- default void onFullyShown() {
- }
-
- /**
- * Invoked when the bouncer is starting to transition to a hidden state.
- */
- default void onStartingToHide() {
- }
-
- /**
- * Invoked when the bouncer is starting to transition to a visible state.
- */
- default void onStartingToShow() {
- }
-
- /**
- * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_HIDDEN}.
- */
- default void onFullyHidden() {
- }
-
- /**
- * From 0f {@link KeyguardBouncer#EXPANSION_VISIBLE} when fully visible
- * to 1f {@link KeyguardBouncer#EXPANSION_HIDDEN} when fully hidden
- */
- default void onExpansionChanged(float bouncerHideAmount) {}
-
- /**
- * Invoked when visibility of KeyguardBouncer has changed.
- * Note the bouncer expansion can be {@link KeyguardBouncer#EXPANSION_VISIBLE}, but the
- * view's visibility can be {@link View.INVISIBLE}.
- */
- default void onVisibilityChanged(boolean isVisible) {}
- }
-
- public interface KeyguardResetCallback {
- void onKeyguardReset();
- }
-
/** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
public static class Factory {
private final Context mContext;
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 4ad319969eaf..cba0897408dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -357,7 +357,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mView.setOnApplyWindowInsetsListener(
(view, windowInsets) -> mView.updateWindowInsets(windowInsets, mInsetsProvider));
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
+ Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
false,
mVolumeSettingObserver,
UserHandle.USER_ALL);
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 48e58fcb584d..6c532a5c5fab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -35,7 +35,6 @@ import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
@@ -58,6 +57,7 @@ import com.android.systemui.privacy.logging.PrivacyLogger;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
@@ -136,6 +136,7 @@ public class PhoneStatusBarPolicy
private final UserInfoController mUserInfoController;
private final IActivityManager mIActivityManager;
private final UserManager mUserManager;
+ private final UserTracker mUserTracker;
private final DevicePolicyManager mDevicePolicyManager;
private final StatusBarIconController mIconController;
private final CommandQueue mCommandQueue;
@@ -176,7 +177,7 @@ public class PhoneStatusBarPolicy
KeyguardStateController keyguardStateController,
LocationController locationController,
SensorPrivacyController sensorPrivacyController, IActivityManager iActivityManager,
- AlarmManager alarmManager, UserManager userManager,
+ AlarmManager alarmManager, UserManager userManager, UserTracker userTracker,
DevicePolicyManager devicePolicyManager, RecordingController recordingController,
@Nullable TelecomManager telecomManager, @DisplayId int displayId,
@Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil,
@@ -196,6 +197,7 @@ public class PhoneStatusBarPolicy
mUserInfoController = userInfoController;
mIActivityManager = iActivityManager;
mUserManager = userManager;
+ mUserTracker = userTracker;
mDevicePolicyManager = devicePolicyManager;
mRotationLockController = rotationLockController;
mDataSaver = dataSaverController;
@@ -366,7 +368,7 @@ public class PhoneStatusBarPolicy
}
private void updateAlarm() {
- final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
+ final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
int zen = mZenController.getZen();
final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
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 f78472386006..80093a3da325 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -791,20 +791,28 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
if (!mScreenOffAnimationController.shouldExpandNotifications()
&& !mAnimatingPanelExpansionOnUnlock
&& !occluding) {
- float behindFraction = getInterpolatedFraction();
- behindFraction = (float) Math.pow(behindFraction, 0.8f);
if (mClipsQsScrim) {
+ float behindFraction = getInterpolatedFraction();
+ behindFraction = (float) Math.pow(behindFraction, 0.8f);
mBehindAlpha = mTransparentScrimBackground ? 0 : 1;
mNotificationsAlpha =
mTransparentScrimBackground ? 0 : behindFraction * mDefaultScrimAlpha;
} else {
- mBehindAlpha =
- mTransparentScrimBackground ? 0 : behindFraction * mDefaultScrimAlpha;
- // Delay fade-in of notification scrim a bit further, to coincide with the
- // view fade in. Otherwise the empty panel can be quite jarring.
- mNotificationsAlpha = mTransparentScrimBackground
- ? 0 : MathUtils.constrainedMap(0f, 1f, 0.3f, 0.75f,
- mPanelExpansionFraction);
+ if (mTransparentScrimBackground) {
+ mBehindAlpha = 0;
+ mNotificationsAlpha = 0;
+ } else {
+ // Behind scrim will finish fading in at 30% expansion.
+ float behindFraction = MathUtils
+ .constrainedMap(0f, 1f, 0f, 0.3f, mPanelExpansionFraction);
+ mBehindAlpha = behindFraction * mDefaultScrimAlpha;
+ // Delay fade-in of notification scrim a bit further, to coincide with the
+ // behind scrim finishing fading in.
+ // Also to coincide with the view starting to fade in, otherwise the empty
+ // panel can be quite jarring.
+ mNotificationsAlpha = MathUtils
+ .constrainedMap(0f, 1f, 0.3f, 0.75f, mPanelExpansionFraction);
+ }
}
mBehindTint = mState.getBehindTint();
mInFrontAlpha = 0;
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 aef25e3f0932..8e22bf4a8df4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -37,7 +37,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
-import android.window.OnBackInvokedCallback;
+import android.window.BackEvent;
+import android.window.OnBackAnimationCallback;
import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
@@ -61,6 +62,7 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.data.BouncerView;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -77,7 +79,6 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.unfold.FoldAodAnimationController;
@@ -198,11 +199,38 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
};
- private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
- if (DEBUG) {
- Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
+ private final OnBackAnimationCallback mOnBackInvokedCallback = new OnBackAnimationCallback() {
+ @Override
+ public void onBackInvoked() {
+ if (DEBUG) {
+ Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
+ }
+ onBackPressed();
+ if (shouldPlayBackAnimation()) {
+ mPrimaryBouncerView.getDelegate().getBackCallback().onBackInvoked();
+ }
+ }
+
+ @Override
+ public void onBackProgressed(BackEvent event) {
+ if (shouldPlayBackAnimation()) {
+ mPrimaryBouncerView.getDelegate().getBackCallback().onBackProgressed(event);
+ }
+ }
+
+ @Override
+ public void onBackCancelled() {
+ if (shouldPlayBackAnimation()) {
+ mPrimaryBouncerView.getDelegate().getBackCallback().onBackCancelled();
+ }
+ }
+
+ @Override
+ public void onBackStarted(BackEvent event) {
+ if (shouldPlayBackAnimation()) {
+ mPrimaryBouncerView.getDelegate().getBackCallback().onBackStarted(event);
+ }
}
- onBackPressed();
};
private boolean mIsBackCallbackRegistered = false;
@@ -256,6 +284,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private boolean mIsModernBouncerEnabled;
private boolean mIsUnoccludeTransitionFlagEnabled;
private boolean mIsModernAlternateBouncerEnabled;
+ private boolean mIsBackAnimationEnabled;
private OnDismissAction mAfterKeyguardGoneAction;
private Runnable mKeyguardGoneCancelAction;
@@ -337,6 +366,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
mAlternateBouncerInteractor = alternateBouncerInteractor;
+ mIsBackAnimationEnabled =
+ featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM);
}
@Override
@@ -472,6 +503,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
}
+ private boolean shouldPlayBackAnimation() {
+ // Suppress back animation when bouncer shouldn't be dismissed on back invocation.
+ return !needsFullscreenBouncer() && mIsBackAnimationEnabled;
+ }
+
@Override
public void onDensityOrFontScaleChanged() {
hideBouncer(true /* destroyView */);
@@ -1111,7 +1147,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
if (hideImmediately) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
} else {
- mNotificationPanelViewController.expandWithoutQs();
+ mNotificationPanelViewController.expandShadeToNotifications();
}
}
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index be6e0cc8a996..078a00d33493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -53,6 +53,7 @@ import com.android.systemui.assist.AssistManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationClickNotifier;
@@ -118,6 +119,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
private final NotificationPanelViewController mNotificationPanel;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
+ private final UserTracker mUserTracker;
private final OnUserInteractionCallback mOnUserInteractionCallback;
private boolean mIsCollapsingToShowActivityOverLockscreen;
@@ -153,7 +155,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
ActivityLaunchAnimator activityLaunchAnimator,
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
LaunchFullScreenIntentProvider launchFullScreenIntentProvider,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ UserTracker userTracker) {
mContext = context;
mMainThreadHandler = mainThreadHandler;
mUiBgExecutor = uiBgExecutor;
@@ -184,6 +187,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mNotificationPanel = panel;
mActivityLaunchAnimator = activityLaunchAnimator;
mNotificationAnimationProvider = notificationAnimationProvider;
+ mUserTracker = userTracker;
launchFullScreenIntentProvider.registerListener(entry -> launchFullScreenIntent(entry));
}
@@ -518,7 +522,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
intent.getPackage(),
(adapter) -> tsb.startActivities(
getActivityOptions(mCentralSurfaces.getDisplayId(), adapter),
- UserHandle.CURRENT));
+ mUserTracker.getUserHandle()));
});
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 9f3fd727be24..be6d5baf8eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -320,7 +320,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mAnimationScheduler.addCallback(this);
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
+ Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
false,
mVolumeSettingObserver,
UserHandle.USER_ALL);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 97b4c2cadbe5..e0d156aa25f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.provider.Settings
import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
@@ -37,6 +38,15 @@ interface MobileConnectionsRepository {
/** Observable for the subscriptionId of the current mobile data connection */
val activeMobileDataSubscriptionId: StateFlow<Int>
+ /**
+ * Observable event for when the active data sim switches but the group stays the same. E.g.,
+ * CBRS switching would trigger this
+ */
+ val activeSubChangedInGroupEvent: Flow<Unit>
+
+ /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */
+ val defaultDataSubId: StateFlow<Int>
+
/** The current connectivity status for the default mobile network connection */
val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index 0c8593d60cf5..b93985604fb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -124,6 +124,9 @@ constructor(
realRepository.activeMobileDataSubscriptionId.value
)
+ override val activeSubChangedInGroupEvent: Flow<Unit> =
+ activeRepo.flatMapLatest { it.activeSubChangedInGroupEvent }
+
override val defaultDataSubRatConfig: StateFlow<MobileMappings.Config> =
activeRepo
.flatMapLatest { it.defaultDataSubRatConfig }
@@ -139,6 +142,11 @@ constructor(
override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
activeRepo.flatMapLatest { it.defaultMobileIconGroup }
+ override val defaultDataSubId: StateFlow<Int> =
+ activeRepo
+ .flatMapLatest { it.defaultDataSubId }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.defaultDataSubId.value)
+
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
activeRepo
.flatMapLatest { it.defaultMobileNetworkConnectivity }
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 22aca0a8b0d7..108834521ebf 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
@@ -48,6 +48,7 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -120,6 +121,9 @@ constructor(
subscriptions.value.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID
)
+ // TODO(b/261029387): consider adding a demo command for this
+ override val activeSubChangedInGroupEvent: Flow<Unit> = flowOf()
+
/** Demo mode doesn't currently support modifications to the mobile mappings */
override val defaultDataSubRatConfig =
MutableStateFlow(MobileMappings.Config.readConfig(context))
@@ -148,8 +152,12 @@ constructor(
private fun <K, V> Map<K, V>.reverse() = entries.associateBy({ it.value }) { it.key }
+ // TODO(b/261029387): add a command for this value
+ override val defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+
// TODO(b/261029387): not yet supported
- override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
+ override val defaultMobileNetworkConnectivity =
+ MutableStateFlow(MobileConnectivityModel(isConnected = true, isValidated = true))
override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository {
val current = connectionRepoCache[subId]?.repo
@@ -229,6 +237,9 @@ constructor(
val connection = getRepoForSubId(subId)
connectionRepoCache[subId]?.lastMobileState = state
+ // 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.Derived(state.name)
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 4472e0972a0b..510482dcb21e 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
@@ -35,6 +35,7 @@ import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.annotation.VisibleForTesting
+import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.R
@@ -52,6 +53,7 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.util.kotlin.pairwiseBy
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -60,9 +62,12 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
@@ -159,10 +164,24 @@ constructor(
.logInputChange(logger, "onActiveDataSubscriptionIdChanged")
.stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
- private val defaultDataSubIdChangedEvent =
+ private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+
+ override val defaultDataSubId: StateFlow<Int> =
broadcastDispatcher
- .broadcastFlow(IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED))
+ .broadcastFlow(
+ IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ ) { intent, _ ->
+ intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+ }
+ .distinctUntilChanged()
.logInputChange(logger, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED")
+ .onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ SubscriptionManager.getDefaultDataSubscriptionId()
+ )
private val carrierConfigChangedEvent =
broadcastDispatcher
@@ -170,7 +189,7 @@ constructor(
.logInputChange(logger, "ACTION_CARRIER_CONFIG_CHANGED")
override val defaultDataSubRatConfig: StateFlow<Config> =
- merge(defaultDataSubIdChangedEvent, carrierConfigChangedEvent)
+ merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
.mapLatest { Config.readConfig(context) }
.distinctUntilChanged()
.logInputChange(logger, "defaultDataSubRatConfig")
@@ -258,6 +277,35 @@ constructor(
.logInputChange(logger, "defaultMobileNetworkConnectivity")
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel())
+ /**
+ * Flow that tracks the active mobile data subscriptions. Emits `true` whenever the active data
+ * subscription Id changes but the subscription group remains the same. In these cases, we want
+ * to retain the previous subscription's validation status for up to 2s to avoid flickering the
+ * icon.
+ *
+ * TODO(b/265164432): we should probably expose all change events, not just same group
+ */
+ @SuppressLint("MissingPermission")
+ override val activeSubChangedInGroupEvent =
+ flow {
+ activeMobileDataSubscriptionId.pairwiseBy { prevVal: Int, newVal: Int ->
+ if (!defaultMobileNetworkConnectivity.value.isValidated) {
+ return@pairwiseBy
+ }
+ val prevSub = subscriptionManager.getActiveSubscriptionInfo(prevVal)
+ val nextSub = subscriptionManager.getActiveSubscriptionInfo(newVal)
+
+ if (prevSub == null || nextSub == null) {
+ return@pairwiseBy
+ }
+
+ if (prevSub.groupUuid != null && prevSub.groupUuid == nextSub.groupUuid) {
+ emit(Unit)
+ }
+ }
+ }
+ .flowOn(bgDispatcher)
+
private fun isValidSubId(subId: Int): Boolean {
subscriptions.value.forEach {
if (it.subscriptionId == subId) {
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 003df2482c6e..9cdff96dc7d9 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
@@ -18,9 +18,11 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.CarrierConfigManager
import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons.NOT_DEFAULT_DATA
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
+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.repository.MobileConnectionRepository
@@ -41,12 +43,29 @@ interface MobileIconInteractor {
/** The current mobile data activity */
val activity: Flow<DataActivityModel>
- /** Only true if mobile is the default transport but is not validated, otherwise false */
- val isDefaultConnectionFailed: StateFlow<Boolean>
+ /**
+ * This bit is meant to be `true` if and only if the default network capabilities (see
+ * [android.net.ConnectivityManager.registerDefaultNetworkCallback]) result in a network that
+ * has the [android.net.NetworkCapabilities.TRANSPORT_CELLULAR] represented.
+ *
+ * Note that this differs from [isDataConnected], which is tracked by telephony and has to do
+ * with the state of using this mobile connection for data as opposed to just voice. It is
+ * possible for a mobile subscription to be connected but not be in a connected data state, and
+ * thus we wouldn't want to show the network type icon.
+ */
+ val isConnected: Flow<Boolean>
- /** True when telephony tells us that the data state is CONNECTED */
+ /**
+ * True when telephony tells us that the data state is CONNECTED. See
+ * [android.telephony.TelephonyCallback.DataConnectionStateListener] for more details. We
+ * consider this connection to be serving data, and thus want to show a network type icon, when
+ * data is connected. Other data connection states would typically cause us not to show the icon
+ */
val isDataConnected: StateFlow<Boolean>
+ /** Only true if mobile is the default transport but is not validated, otherwise false */
+ val isDefaultConnectionFailed: StateFlow<Boolean>
+
/** True if we consider this connection to be in service, i.e. can make calls */
val isInService: StateFlow<Boolean>
@@ -100,8 +119,10 @@ class MobileIconInteractorImpl(
defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
override val alwaysShowDataRatIcon: StateFlow<Boolean>,
override val alwaysUseCdmaLevel: StateFlow<Boolean>,
+ defaultMobileConnectivity: StateFlow<MobileConnectivityModel>,
defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
+ defaultDataSubId: StateFlow<Int>,
override val isDefaultConnectionFailed: StateFlow<Boolean>,
connectionRepository: MobileConnectionRepository,
) : MobileIconInteractor {
@@ -111,8 +132,19 @@ class MobileIconInteractorImpl(
override val activity = connectionInfo.mapLatest { it.dataActivityDirection }
+ override val isConnected: Flow<Boolean> = defaultMobileConnectivity.mapLatest { it.isConnected }
+
override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
+ private val isDefault =
+ defaultDataSubId
+ .mapLatest { connectionRepository.subId == it }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ connectionRepository.subId == defaultDataSubId.value
+ )
+
override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
override val networkName =
@@ -137,7 +169,12 @@ class MobileIconInteractorImpl(
connectionInfo,
defaultMobileIconMapping,
defaultMobileIconGroup,
- ) { info, mapping, defaultGroup ->
+ isDefault,
+ ) { info, mapping, defaultGroup, isDefault ->
+ if (!isDefault) {
+ return@combine NOT_DEFAULT_DATA
+ }
+
when (info.resolvedNetworkType) {
is ResolvedNetworkType.CarrierMergedNetworkType ->
info.resolvedNetworkType.iconGroupOverride
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 83da1dd06780..9ae38e973bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -23,6 +23,7 @@ import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+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.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
@@ -31,14 +32,17 @@ import com.android.systemui.util.CarrierConfigTracker
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformLatest
/**
* Business layer logic for the set of mobile subscription icons.
@@ -62,6 +66,17 @@ interface MobileIconsInteractor {
/** True if the CDMA level should be preferred over the primary level. */
val alwaysUseCdmaLevel: StateFlow<Boolean>
+ /** Tracks the subscriptionId set as the default for data connections */
+ val defaultDataSubId: StateFlow<Int>
+
+ /**
+ * The connectivity of the default mobile network. Note that this can differ from what is
+ * reported from [MobileConnectionsRepository] in some cases. E.g., when the active subscription
+ * changes but the groupUuid remains the same, we keep the old validation information for 2
+ * seconds to avoid icon flickering.
+ */
+ val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel>
+
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
/** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
@@ -154,6 +169,48 @@ constructor(
}
}
+ override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId
+
+ /**
+ * Copied from the old pipeline. We maintain a 2s period of time where we will keep the
+ * validated bit from the old active network (A) while data is changing to the new one (B).
+ *
+ * This condition only applies if
+ * 1. A and B are in the same subscription group (e.c. for CBRS data switching) and
+ * 2. A was validated before the switch
+ *
+ * The goal of this is to minimize the flickering in the UI of the cellular indicator
+ */
+ private val forcingCellularValidation =
+ mobileConnectionsRepo.activeSubChangedInGroupEvent
+ .filter { mobileConnectionsRepo.defaultMobileNetworkConnectivity.value.isValidated }
+ .transformLatest {
+ emit(true)
+ delay(2000)
+ emit(false)
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
+ combine(
+ mobileConnectionsRepo.defaultMobileNetworkConnectivity,
+ forcingCellularValidation,
+ ) { networkConnectivity, forceValidation ->
+ return@combine if (forceValidation) {
+ MobileConnectivityModel(
+ isValidated = true,
+ isConnected = networkConnectivity.isConnected
+ )
+ } else {
+ networkConnectivity
+ }
+ }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ mobileConnectionsRepo.defaultMobileNetworkConnectivity.value
+ )
+
/**
* Mapping from network type to [MobileIconGroup] using the config generated for the default
* subscription Id. This mapping is the same for every subscription.
@@ -207,8 +264,10 @@ constructor(
activeDataConnectionHasDataEnabled,
alwaysShowDataRatIcon,
alwaysUseCdmaLevel,
+ defaultMobileNetworkConnectivity,
defaultMobileIconMapping,
defaultMobileIconGroup,
+ defaultDataSubId,
isDefaultConnectionFailed,
mobileConnectionsRepo.getRepoForSubId(subId),
)
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 a2117c7df188..5e9356163e6e 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
@@ -102,24 +102,29 @@ constructor(
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
}
+ private val showNetworkTypeIcon: Flow<Boolean> =
+ combine(
+ iconInteractor.isDataConnected,
+ iconInteractor.isDataEnabled,
+ iconInteractor.isDefaultConnectionFailed,
+ iconInteractor.alwaysShowDataRatIcon,
+ iconInteractor.isConnected,
+ ) { dataConnected, dataEnabled, failedConnection, alwaysShow, connected ->
+ alwaysShow || (dataConnected && dataEnabled && !failedConnection && connected)
+ }
+
override val networkTypeIcon: Flow<Icon?> =
combine(
iconInteractor.networkTypeIconGroup,
- iconInteractor.isDataConnected,
- iconInteractor.isDataEnabled,
- iconInteractor.isDefaultConnectionFailed,
- iconInteractor.alwaysShowDataRatIcon,
- ) { networkTypeIconGroup, dataConnected, dataEnabled, failedConnection, alwaysShow ->
+ showNetworkTypeIcon,
+ ) { networkTypeIconGroup, shouldShow ->
val desc =
if (networkTypeIconGroup.dataContentDescription != 0)
ContentDescription.Resource(networkTypeIconGroup.dataContentDescription)
else null
val icon = Icon.Resource(networkTypeIconGroup.dataType, desc)
return@combine when {
- alwaysShow -> icon
- !dataConnected -> null
- !dataEnabled -> null
- failedConnection -> null
+ !shouldShow -> null
else -> icon
}
}
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
new file mode 100644
index 000000000000..e092f01d19f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.telephony.ui.activity
+
+import android.app.ActivityOptions
+import android.content.DialogInterface
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.os.UserHandle
+import android.util.Log
+import android.view.WindowManager
+import com.android.internal.app.AlertActivity
+import com.android.systemui.R
+
+/** Dialog shown to the user to switch to managed profile for making a call using work SIM. */
+class SwitchToManagedProfileForCallActivity : AlertActivity(), DialogInterface.OnClickListener {
+ private lateinit var phoneNumber: Uri
+ private var managedProfileUserId = UserHandle.USER_NULL
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ window.addSystemFlags(
+ WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
+ )
+ super.onCreate(savedInstanceState)
+
+ phoneNumber = intent.getData()
+ managedProfileUserId =
+ intent.getIntExtra(
+ "android.telecom.extra.MANAGED_PROFILE_USER_ID",
+ UserHandle.USER_NULL
+ )
+
+ mAlertParams.apply {
+ mTitle = getString(R.string.call_from_work_profile_title)
+ mMessage = getString(R.string.call_from_work_profile_text)
+ mPositiveButtonText = getString(R.string.call_from_work_profile_action)
+ mNegativeButtonText = getString(R.string.call_from_work_profile_close)
+ mPositiveButtonListener = this@SwitchToManagedProfileForCallActivity
+ mNegativeButtonListener = this@SwitchToManagedProfileForCallActivity
+ }
+ setupAlert()
+ }
+
+ override fun onClick(dialog: DialogInterface?, which: Int) {
+ if (which == BUTTON_POSITIVE) {
+ switchToManagedProfile()
+ }
+ finish()
+ }
+
+ private fun switchToManagedProfile() {
+ try {
+ applicationContext.startActivityAsUser(
+ Intent(Intent.ACTION_DIAL, phoneNumber),
+ ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(),
+ UserHandle.of(managedProfileUserId)
+ )
+ } catch (e: Exception) {
+ Log.e(TAG, "Failed to launch activity", e)
+ }
+ }
+
+ companion object {
+ private const val TAG = "SwitchToManagedProfileForCallActivity"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index ad48e218687d..df8d16142b8b 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS
import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS
import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT
import androidx.annotation.CallSuper
+import androidx.annotation.VisibleForTesting
import com.android.systemui.CoreStartable
import com.android.systemui.Dumpable
import com.android.systemui.dagger.qualifiers.Main
@@ -108,9 +109,10 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
* Whenever the current view disappears, the next-priority view will be displayed if it's still
* valid.
*/
+ @VisibleForTesting
internal val activeViews: MutableList<DisplayInfo> = mutableListOf()
- private fun getCurrentDisplayInfo(): DisplayInfo? {
+ internal fun getCurrentDisplayInfo(): DisplayInfo? {
return activeViews.getOrNull(0)
}
@@ -119,15 +121,26 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
dumpManager.registerNormalDumpable(this)
}
+ private val listeners: MutableSet<Listener> = mutableSetOf()
+
+ /** Registers a listener. */
+ fun registerListener(listener: Listener) {
+ listeners.add(listener)
+ }
+
+ /** Unregisters a listener. */
+ fun unregisterListener(listener: Listener) {
+ listeners.remove(listener)
+ }
+
/**
* Displays the view with the provided [newInfo].
*
* This method handles inflating and attaching the view, then delegates to [updateView] to
* display the correct information in the view.
- * @param onViewTimeout a runnable that runs after the view timeout.
*/
@Synchronized
- fun displayView(newInfo: T, onViewTimeout: Runnable? = null) {
+ fun displayView(newInfo: T) {
val timeout = accessibilityManager.getRecommendedTimeoutMillis(
newInfo.timeoutMs,
// Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
@@ -146,14 +159,13 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
logger.logViewUpdate(newInfo)
currentDisplayInfo.info = newInfo
currentDisplayInfo.timeExpirationMillis = timeExpirationMillis
- updateTimeout(currentDisplayInfo, timeout, onViewTimeout)
+ updateTimeout(currentDisplayInfo, timeout)
updateView(newInfo, view)
return
}
val newDisplayInfo = DisplayInfo(
info = newInfo,
- onViewTimeout = onViewTimeout,
timeExpirationMillis = timeExpirationMillis,
// Null values will be updated to non-null if/when this view actually gets displayed
view = null,
@@ -196,7 +208,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
private fun showNewView(newDisplayInfo: DisplayInfo, timeout: Int) {
logger.logViewAddition(newDisplayInfo.info)
createAndAcquireWakeLock(newDisplayInfo)
- updateTimeout(newDisplayInfo, timeout, newDisplayInfo.onViewTimeout)
+ updateTimeout(newDisplayInfo, timeout)
inflateAndUpdateView(newDisplayInfo)
}
@@ -227,19 +239,16 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
/**
* Creates a runnable that will remove [displayInfo] in [timeout] ms from now.
*
- * @param onViewTimeout an optional runnable that will be run if the view times out.
* @return a runnable that, when run, will *cancel* the view's timeout.
*/
- private fun updateTimeout(displayInfo: DisplayInfo, timeout: Int, onViewTimeout: Runnable?) {
+ private fun updateTimeout(displayInfo: DisplayInfo, timeout: Int) {
val cancelViewTimeout = mainExecutor.executeDelayed(
{
removeView(displayInfo.info.id, REMOVAL_REASON_TIMEOUT)
- onViewTimeout?.run()
},
timeout.toLong()
)
- displayInfo.onViewTimeout = onViewTimeout
// Cancel old view timeout and re-set it.
displayInfo.cancelViewTimeout?.run()
displayInfo.cancelViewTimeout = cancelViewTimeout
@@ -317,6 +326,9 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
// event comes in while this view is animating out, we still display the new view
// appropriately.
activeViews.remove(displayInfo)
+ listeners.forEach {
+ it.onInfoPermanentlyRemoved(id)
+ }
// No need to time the view out since it's already gone
displayInfo.cancelViewTimeout?.run()
@@ -380,6 +392,9 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
invalidViews.forEach {
activeViews.remove(it)
logger.logViewExpiration(it.info)
+ listeners.forEach { listener ->
+ listener.onInfoPermanentlyRemoved(it.info.id)
+ }
}
}
@@ -436,6 +451,15 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
onAnimationEnd.run()
}
+ /** A listener interface to be notified of various view events. */
+ fun interface Listener {
+ /**
+ * Called whenever a [DisplayInfo] with the given [id] has been removed and will never be
+ * displayed again (unless another call to [updateView] is made).
+ */
+ fun onInfoPermanentlyRemoved(id: String)
+ }
+
/** A container for all the display-related state objects. */
inner class DisplayInfo(
/**
@@ -461,11 +485,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
var wakeLock: WakeLock?,
/**
- * See [displayView].
- */
- var onViewTimeout: Runnable?,
-
- /**
* A runnable that, when run, will cancel this view's timeout.
*
* Null if this info isn't currently being displayed.
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index 04b1a5016989..9e0bbb7624bd 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -80,6 +80,7 @@ constructor(
powerManager: PowerManager,
private val falsingManager: FalsingManager,
private val falsingCollector: FalsingCollector,
+ private val swipeChipbarAwayGestureHandler: SwipeChipbarAwayGestureHandler?,
private val viewUtil: ViewUtil,
private val vibratorHelper: VibratorHelper,
wakeLockBuilder: WakeLock.Builder,
@@ -105,6 +106,8 @@ constructor(
commonWindowLayoutParams.apply { gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) }
override fun updateView(newInfo: ChipbarInfo, currentView: ViewGroup) {
+ updateGestureListening()
+
logger.logViewUpdate(
newInfo.windowTitle,
newInfo.text.loadText(context),
@@ -228,6 +231,42 @@ constructor(
includeMargins = true,
onAnimationEnd,
)
+
+ updateGestureListening()
+ }
+
+ private fun updateGestureListening() {
+ if (swipeChipbarAwayGestureHandler == null) {
+ return
+ }
+
+ val currentDisplayInfo = getCurrentDisplayInfo()
+ if (currentDisplayInfo != null && currentDisplayInfo.info.allowSwipeToDismiss) {
+ swipeChipbarAwayGestureHandler.setViewFetcher { currentDisplayInfo.view }
+ swipeChipbarAwayGestureHandler.addOnGestureDetectedCallback(TAG) {
+ onSwipeUpGestureDetected()
+ }
+ } else {
+ swipeChipbarAwayGestureHandler.resetViewFetcher()
+ swipeChipbarAwayGestureHandler.removeOnGestureDetectedCallback(TAG)
+ }
+ }
+
+ private fun onSwipeUpGestureDetected() {
+ val currentDisplayInfo = getCurrentDisplayInfo()
+ if (currentDisplayInfo == null) {
+ logger.logSwipeGestureError(id = null, errorMsg = "No info is being displayed")
+ return
+ }
+ if (!currentDisplayInfo.info.allowSwipeToDismiss) {
+ logger.logSwipeGestureError(
+ id = currentDisplayInfo.info.id,
+ errorMsg = "This view prohibits swipe-to-dismiss",
+ )
+ return
+ }
+ removeView(currentDisplayInfo.info.id, SWIPE_UP_GESTURE_REASON)
+ updateGestureListening()
}
private fun ViewGroup.getInnerView(): ViewGroup {
@@ -250,3 +289,5 @@ constructor(
private const val ANIMATION_IN_DURATION = 500L
private const val ANIMATION_OUT_DURATION = 250L
@IdRes private val INFO_TAG = R.id.tag_chipbar_info
+private const val SWIPE_UP_GESTURE_REASON = "SWIPE_UP_GESTURE_DETECTED"
+private const val TAG = "ChipbarCoordinator"
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 dd4bd26e3bcd..fe46318daa30 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
@@ -33,12 +33,14 @@ import com.android.systemui.temporarydisplay.ViewPriority
* @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).
* @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.
*/
data class ChipbarInfo(
val startIcon: TintedIcon,
val text: Text,
val endItem: ChipbarEndItem?,
val vibrationEffect: VibrationEffect? = null,
+ val allowSwipeToDismiss: Boolean = false,
override val windowTitle: String,
override val wakeReason: String,
override val timeoutMs: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
index fcfbe0aeedf6..f23942847e68 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
@@ -46,4 +46,16 @@ constructor(
{ "Chipbar updated. window=$str1 text=$str2 endItem=$str3" }
)
}
+
+ fun logSwipeGestureError(id: String?, errorMsg: String) {
+ buffer.log(
+ tag,
+ LogLevel.WARNING,
+ {
+ str1 = id
+ str2 = errorMsg
+ },
+ { "Chipbar swipe gesture detected for incorrect state. id=$str1 error=$str2" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt
new file mode 100644
index 000000000000..6e3cb4823afa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay.chipbar
+
+import android.content.Context
+import android.view.MotionEvent
+import android.view.View
+import com.android.systemui.statusbar.gesture.SwipeUpGestureHandler
+import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
+import com.android.systemui.util.boundsOnScreen
+
+/**
+ * A class to detect when a user has swiped the chipbar away.
+ *
+ * Effectively [SysUISingleton]. But, this shouldn't be created if the gesture isn't enabled. See
+ * [TemporaryDisplayModule.provideSwipeChipbarAwayGestureHandler].
+ */
+class SwipeChipbarAwayGestureHandler(
+ context: Context,
+ logger: SwipeUpGestureLogger,
+) : SwipeUpGestureHandler(context, logger, loggerTag = LOGGER_TAG) {
+
+ private var viewFetcher: () -> View? = { null }
+
+ override fun startOfGestureIsWithinBounds(ev: MotionEvent): Boolean {
+ val view = viewFetcher.invoke() ?: return false
+ // Since chipbar is in its own window, we need to use [boundsOnScreen] to get an accurate
+ // bottom. ([view.bottom] would be relative to its window, which would be too small.)
+ val viewBottom = view.boundsOnScreen.bottom
+ // Allow the gesture to start a bit below the chipbar
+ return ev.y <= 1.5 * viewBottom
+ }
+
+ /**
+ * Sets a fetcher that returns the current chipbar view. The fetcher will be invoked whenever a
+ * gesture starts to determine if the gesture is near the chipbar.
+ */
+ fun setViewFetcher(fetcher: () -> View?) {
+ viewFetcher = fetcher
+ }
+
+ /** Removes the current view fetcher. */
+ fun resetViewFetcher() {
+ viewFetcher = { null }
+ }
+}
+
+private const val LOGGER_TAG = "SwipeChipbarAway"
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
index cf0a1835c8e8..933c0604a3b9 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
@@ -16,22 +16,38 @@
package com.android.systemui.temporarydisplay.dagger
+import android.content.Context
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
+import com.android.systemui.temporarydisplay.chipbar.SwipeChipbarAwayGestureHandler
import dagger.Module
import dagger.Provides
@Module
interface TemporaryDisplayModule {
- @Module
companion object {
- @JvmStatic
@Provides
@SysUISingleton
@ChipbarLog
fun provideChipbarLogBuffer(factory: LogBufferFactory): LogBuffer {
return factory.create("ChipbarLog", 40)
}
+
+ @Provides
+ @SysUISingleton
+ fun provideSwipeChipbarAwayGestureHandler(
+ mediaTttFlags: MediaTttFlags,
+ context: Context,
+ logger: SwipeUpGestureLogger,
+ ): SwipeChipbarAwayGestureHandler? {
+ return if (mediaTttFlags.isMediaTttDismissGestureEnabled()) {
+ SwipeChipbarAwayGestureHandler(context, logger)
+ } else {
+ null
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 3ecb15b9d79c..f29ca4d30ccb 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -26,7 +26,6 @@ import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_INDEX
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_SOURCE;
import static com.android.systemui.theme.ThemeOverlayApplier.TIMESTAMP_FIELD;
-import android.annotation.Nullable;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.app.WallpaperManager.OnColorsChangedListener;
@@ -70,6 +69,7 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.monet.Style;
+import com.android.systemui.monet.TonalPalette;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -391,7 +391,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
UserHandle.ALL);
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
+ Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
false,
new ContentObserver(mBgHandler) {
@Override
@@ -513,39 +513,42 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
/**
* Given a color candidate, return an overlay definition.
*/
- protected @Nullable FabricatedOverlay getOverlay(int color, int type, Style style) {
+ protected FabricatedOverlay getOverlay(int color, int type, Style style) {
boolean nightMode = (mResources.getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
mColorScheme = new ColorScheme(color, nightMode, style);
- List<Integer> colorShades = type == ACCENT
- ? mColorScheme.getAllAccentColors() : mColorScheme.getAllNeutralColors();
String name = type == ACCENT ? "accent" : "neutral";
- int paletteSize = mColorScheme.getAccent1().size();
+
FabricatedOverlay.Builder overlay =
new FabricatedOverlay.Builder("com.android.systemui", name, "android");
- for (int i = 0; i < colorShades.size(); i++) {
- int luminosity = i % paletteSize;
- int paletteIndex = i / paletteSize + 1;
- String resourceName;
- switch (luminosity) {
- case 0:
- resourceName = "android:color/system_" + name + paletteIndex + "_10";
- break;
- case 1:
- resourceName = "android:color/system_" + name + paletteIndex + "_50";
- break;
- default:
- int l = luminosity - 1;
- resourceName = "android:color/system_" + name + paletteIndex + "_" + l + "00";
- }
- overlay.setResourceValue(resourceName, TypedValue.TYPE_INT_COLOR_ARGB8,
- ColorUtils.setAlphaComponent(colorShades.get(i), 0xFF));
+
+ if (type == ACCENT) {
+ assignTonalPaletteToOverlay("accent1", overlay, mColorScheme.getAccent1());
+ assignTonalPaletteToOverlay("accent2", overlay, mColorScheme.getAccent2());
+ assignTonalPaletteToOverlay("accent3", overlay, mColorScheme.getAccent3());
+ } else {
+ assignTonalPaletteToOverlay("neutral1", overlay, mColorScheme.getNeutral1());
+ assignTonalPaletteToOverlay("neutral2", overlay, mColorScheme.getNeutral2());
}
return overlay.build();
}
+ private void assignTonalPaletteToOverlay(String name,
+ FabricatedOverlay.Builder overlay, TonalPalette tonalPalette) {
+
+ String resourcePrefix = "android:color/system_" + name;
+ int colorDataType = TypedValue.TYPE_INT_COLOR_ARGB8;
+
+ tonalPalette.getAllShadesMapped().forEach((key, value) -> {
+ String resourceName = resourcePrefix + "_" + key;
+ int colorValue = ColorUtils.setAlphaComponent(value, 0xFF);
+ overlay.setResourceValue(resourceName, colorDataType,
+ colorValue);
+ });
+ }
+
/**
* Checks if the color scheme in mColorScheme matches the current system palettes.
* @param managedProfiles List of managed profiles for this user.
@@ -557,15 +560,15 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
Resources res = userHandle.isSystem()
? mResources : mContext.createContextAsUser(userHandle, 0).getResources();
if (!(res.getColor(android.R.color.system_accent1_500, mContext.getTheme())
- == mColorScheme.getAccent1().get(6)
+ == mColorScheme.getAccent1().getS500()
&& res.getColor(android.R.color.system_accent2_500, mContext.getTheme())
- == mColorScheme.getAccent2().get(6)
+ == mColorScheme.getAccent2().getS500()
&& res.getColor(android.R.color.system_accent3_500, mContext.getTheme())
- == mColorScheme.getAccent3().get(6)
+ == mColorScheme.getAccent3().getS500()
&& res.getColor(android.R.color.system_neutral1_500, mContext.getTheme())
- == mColorScheme.getNeutral1().get(6)
+ == mColorScheme.getNeutral1().getS500()
&& res.getColor(android.R.color.system_neutral2_500, mContext.getTheme())
- == mColorScheme.getNeutral2().get(6))) {
+ == mColorScheme.getNeutral2().getS500())) {
return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 523cf68891a0..0069bb545ef4 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -36,6 +36,8 @@ import android.view.SurfaceSession
import android.view.WindowManager
import android.view.WindowlessWindowManager
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.LinearLightRevealEffect
@@ -57,6 +59,7 @@ class UnfoldLightRevealOverlayAnimation
@Inject
constructor(
private val context: Context,
+ private val featureFlags: FeatureFlags,
private val deviceStateManager: DeviceStateManager,
private val contentResolver: ContentResolver,
private val displayManager: DisplayManager,
@@ -81,6 +84,7 @@ constructor(
private var scrimView: LightRevealScrim? = null
private var isFolded: Boolean = false
private var isUnfoldHandled: Boolean = true
+ private var overlayAddReason: AddOverlayReason? = null
private var currentRotation: Int = context.display!!.rotation
@@ -158,6 +162,8 @@ constructor(
ensureInBackground()
ensureOverlayRemoved()
+ overlayAddReason = reason
+
val newRoot = SurfaceControlViewHost(context, context.display!!, wwm)
val params = getLayoutParams()
val newView =
@@ -170,11 +176,7 @@ constructor(
.apply {
revealEffect = createLightRevealEffect()
isScrimOpaqueChangedListener = Consumer {}
- revealAmount =
- when (reason) {
- FOLD -> TRANSPARENT
- UNFOLD -> BLACK
- }
+ revealAmount = calculateRevealAmount()
}
newRoot.setView(newView, params)
@@ -207,6 +209,31 @@ constructor(
root = newRoot
}
+ private fun calculateRevealAmount(animationProgress: Float? = null): Float {
+ val overlayAddReason = overlayAddReason ?: UNFOLD
+
+ if (animationProgress == null) {
+ // Animation progress is unknown, calculate the initial value based on the overlay
+ // add reason
+ return when (overlayAddReason) {
+ FOLD -> TRANSPARENT
+ UNFOLD -> BLACK
+ }
+ }
+
+ val showVignetteWhenFolding =
+ featureFlags.isEnabled(Flags.ENABLE_DARK_VIGNETTE_WHEN_FOLDING)
+
+ return if (!showVignetteWhenFolding && overlayAddReason == FOLD) {
+ // Do not darken the content when SHOW_VIGNETTE_WHEN_FOLDING flag is off
+ // and we are folding the device. We still add the overlay to block touches
+ // while the animation is running but the overlay is transparent.
+ TRANSPARENT
+ } else {
+ animationProgress
+ }
+ }
+
private fun getLayoutParams(): WindowManager.LayoutParams {
val params: WindowManager.LayoutParams = WindowManager.LayoutParams()
@@ -259,7 +286,7 @@ constructor(
private inner class TransitionListener : TransitionProgressListener {
override fun onTransitionProgress(progress: Float) {
- executeInBackground { scrimView?.revealAmount = progress }
+ executeInBackground { scrimView?.revealAmount = calculateRevealAmount(progress) }
}
override fun onTransitionFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt
index a9d66de118e0..5a25a4e25afc 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt
@@ -63,11 +63,10 @@ class AddUserDialog(
}
// Use broadcast instead of ShadeController, as this dialog may have started in
- // another
- // process where normal dagger bindings are not available.
+ // another process where normal dagger bindings are not available.
broadcastSender.sendBroadcastAsUser(
Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
- UserHandle.CURRENT
+ userHandle
)
context.startActivityAsUser(
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index b61b2e66fb22..47d505ea36d5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -16,14 +16,21 @@
package com.android.systemui.util.kotlin
+import com.android.systemui.util.time.SystemClock
+import com.android.systemui.util.time.SystemClockImpl
+import kotlinx.coroutines.CoroutineStart
import java.util.concurrent.atomic.AtomicReference
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
+import kotlin.math.max
/**
* Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
@@ -167,3 +174,89 @@ fun <A, B, C> Flow<A>.sample(other: Flow<B>, transform: suspend (A, B) -> C): Fl
* Note that the returned Flow will not emit anything until [other] has emitted at least one value.
*/
fun <A> Flow<*>.sample(other: Flow<A>): Flow<A> = sample(other) { _, a -> a }
+
+/**
+ * Returns a flow that mirrors the original flow, but delays values following emitted values for the
+ * given [periodMs]. If the original flow emits more than one value during this period, only the
+ * latest value is emitted.
+ *
+ * Example:
+ *
+ * ```kotlin
+ * flow {
+ * emit(1) // t=0ms
+ * delay(90)
+ * emit(2) // t=90ms
+ * delay(90)
+ * emit(3) // t=180ms
+ * delay(1010)
+ * emit(4) // t=1190ms
+ * delay(1010)
+ * emit(5) // t=2200ms
+ * }.throttle(1000)
+ * ```
+ *
+ * produces the following emissions at the following times
+ *
+ * ```text
+ * 1 (t=0ms), 3 (t=1000ms), 4 (t=2000ms), 5 (t=3000ms)
+ * ```
+ */
+fun <T> Flow<T>.throttle(periodMs: Long): Flow<T> = this.throttle(periodMs, SystemClockImpl())
+
+/**
+ * Returns a flow that mirrors the original flow, but delays values following emitted values for the
+ * given [periodMs] as reported by the given [clock]. If the original flow emits more than one value
+ * during this period, only The latest value is emitted.
+ *
+ * Example:
+ *
+ * ```kotlin
+ * flow {
+ * emit(1) // t=0ms
+ * delay(90)
+ * emit(2) // t=90ms
+ * delay(90)
+ * emit(3) // t=180ms
+ * delay(1010)
+ * emit(4) // t=1190ms
+ * delay(1010)
+ * emit(5) // t=2200ms
+ * }.throttle(1000)
+ * ```
+ *
+ * produces the following emissions at the following times
+ *
+ * ```text
+ * 1 (t=0ms), 3 (t=1000ms), 4 (t=2000ms), 5 (t=3000ms)
+ * ```
+ */
+fun <T> Flow<T>.throttle(periodMs: Long, clock: SystemClock): Flow<T> = channelFlow {
+ coroutineScope {
+ var previousEmitTimeMs = 0L
+ var delayJob: Job? = null
+ var sendJob: Job? = null
+ val outerScope = this
+
+ collect {
+ delayJob?.cancel()
+ sendJob?.join()
+ val currentTimeMs = clock.elapsedRealtime()
+ val timeSinceLastEmit = currentTimeMs - previousEmitTimeMs
+ val timeUntilNextEmit = max(0L, periodMs - timeSinceLastEmit)
+ if (timeUntilNextEmit > 0L) {
+ // We create delayJob to allow cancellation during the delay period
+ delayJob = launch {
+ delay(timeUntilNextEmit)
+ sendJob = outerScope.launch(start = CoroutineStart.UNDISPATCHED) {
+ send(it)
+ previousEmitTimeMs = clock.elapsedRealtime()
+ }
+ }
+ } else {
+ send(it)
+ previousEmitTimeMs = currentTimeMs
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
index 4351afe68339..a0d22f388cbc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
@@ -29,12 +29,12 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Debug;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.util.Log;
import androidx.core.content.FileProvider;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.settings.UserTracker;
import com.google.android.collect.Lists;
@@ -62,13 +62,15 @@ public class LeakReporter {
static final String LEAK_DUMP = "leak.dump";
private final Context mContext;
+ private final UserTracker mUserTracker;
private final LeakDetector mLeakDetector;
private final String mLeakReportEmail;
@Inject
- public LeakReporter(Context context, LeakDetector leakDetector,
+ public LeakReporter(Context context, UserTracker userTracker, LeakDetector leakDetector,
@Nullable @Named(LEAK_REPORT_EMAIL_NAME) String leakReportEmail) {
mContext = context;
+ mUserTracker = userTracker;
mLeakDetector = leakDetector;
mLeakReportEmail = leakReportEmail;
}
@@ -111,7 +113,7 @@ public class LeakReporter {
getIntent(hprofFile, dumpFile),
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
null,
- UserHandle.CURRENT));
+ mUserTracker.getUserHandle()));
notiMan.notify(TAG, 0, builder.build());
} catch (IOException e) {
Log.e(TAG, "Couldn't dump heap for leak", e);
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
index 0b2f004537d6..31f35fc076a1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -1,15 +1,17 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.leak;
@@ -26,7 +28,27 @@ import android.view.Surface;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-public class RotationUtils {
+/**
+ * Utility class that provides device orientation.
+ *
+ * <p>Consider using {@link Surface.Rotation} or add a function that respects device aspect ratio
+ * and {@code android.internal.R.bool.config_reverseDefaultRotation}.
+ *
+ * <p>If you only care about the rotation, use {@link Surface.Rotation}, as it always gives the
+ * counter clock-wise rotation. (e.g. If you have a device that has a charging port at the bottom,
+ * rotating three times in counter clock direction will give you {@link Surface#ROTATION_270} while
+ * having the charging port on the left side of the device.)
+ *
+ * <p>If you need whether the device is in portrait or landscape (or their opposites), please add a
+ * function here that respects the device aspect ratio and
+ * {@code android.internal.R.bool.config_reverseDefaultRotation} together.
+ *
+ * <p>Note that {@code android.internal.R.bool.config_reverseDefaultRotation} does not change the
+ * winding order. In other words, the rotation order (counter clock-wise) will remain the same. It
+ * only flips the device orientation, such that portrait becomes upside down, landscape becomes
+ * seascape.
+ */
+public final class RotationUtils {
public static final int ROTATION_NONE = 0;
public static final int ROTATION_LANDSCAPE = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 1a30b0a8d8bf..85fada20a7ad 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -20,14 +20,18 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
+import com.android.systemui.settings.UserTracker;
+
import javax.inject.Inject;
class GlobalSettingsImpl implements GlobalSettings {
private final ContentResolver mContentResolver;
+ private final UserTracker mUserTracker;
@Inject
- GlobalSettingsImpl(ContentResolver contentResolver) {
+ GlobalSettingsImpl(ContentResolver contentResolver, UserTracker userTracker) {
mContentResolver = contentResolver;
+ mUserTracker = userTracker;
}
@Override
@@ -36,13 +40,19 @@ class GlobalSettingsImpl implements GlobalSettings {
}
@Override
+ public UserTracker getUserTracker() {
+ return mUserTracker;
+ }
+
+ @Override
public Uri getUriFor(String name) {
return Settings.Global.getUriFor(name);
}
@Override
public String getStringForUser(String name, int userHandle) {
- return Settings.Global.getStringForUser(mContentResolver, name, userHandle);
+ return Settings.Global.getStringForUser(mContentResolver, name,
+ getRealUserHandle(userHandle));
}
@Override
@@ -53,14 +63,16 @@ class GlobalSettingsImpl implements GlobalSettings {
@Override
public boolean putStringForUser(String name, String value, int userHandle) {
- return Settings.Global.putStringForUser(mContentResolver, name, value, userHandle);
+ return Settings.Global.putStringForUser(mContentResolver, name, value,
+ getRealUserHandle(userHandle));
}
@Override
public boolean putStringForUser(String name, String value, String tag, boolean makeDefault,
int userHandle, boolean overrideableByRestore) {
return Settings.Global.putStringForUser(
- mContentResolver, name, value, tag, makeDefault, userHandle, overrideableByRestore);
+ mContentResolver, name, value, tag, makeDefault, getRealUserHandle(userHandle),
+ overrideableByRestore);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
index 020c234191e0..f995436594b1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -20,14 +20,18 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
+import com.android.systemui.settings.UserTracker;
+
import javax.inject.Inject;
class SecureSettingsImpl implements SecureSettings {
private final ContentResolver mContentResolver;
+ private final UserTracker mUserTracker;
@Inject
- SecureSettingsImpl(ContentResolver contentResolver) {
+ SecureSettingsImpl(ContentResolver contentResolver, UserTracker userTracker) {
mContentResolver = contentResolver;
+ mUserTracker = userTracker;
}
@Override
@@ -36,13 +40,19 @@ class SecureSettingsImpl implements SecureSettings {
}
@Override
+ public UserTracker getUserTracker() {
+ return mUserTracker;
+ }
+
+ @Override
public Uri getUriFor(String name) {
return Settings.Secure.getUriFor(name);
}
@Override
public String getStringForUser(String name, int userHandle) {
- return Settings.Secure.getStringForUser(mContentResolver, name, userHandle);
+ return Settings.Secure.getStringForUser(mContentResolver, name,
+ getRealUserHandle(userHandle));
}
@Override
@@ -52,14 +62,16 @@ class SecureSettingsImpl implements SecureSettings {
@Override
public boolean putStringForUser(String name, String value, int userHandle) {
- return Settings.Secure.putStringForUser(mContentResolver, name, value, userHandle);
+ return Settings.Secure.putStringForUser(mContentResolver, name, value,
+ getRealUserHandle(userHandle));
}
@Override
public boolean putStringForUser(String name, String value, String tag, boolean makeDefault,
int userHandle, boolean overrideableByRestore) {
return Settings.Secure.putStringForUser(
- mContentResolver, name, value, tag, makeDefault, userHandle, overrideableByRestore);
+ mContentResolver, name, value, tag, makeDefault, getRealUserHandle(userHandle),
+ overrideableByRestore);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
index 1bf5f076ac2f..b6846a34a0bd 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
@@ -22,8 +22,11 @@ import android.annotation.UserIdInt;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.UserHandle;
import android.provider.Settings;
+import com.android.systemui.settings.UserTracker;
+
/**
* Used to interact with Settings.Secure, Settings.Global, and Settings.System.
*
@@ -46,6 +49,11 @@ public interface SettingsProxy {
ContentResolver getContentResolver();
/**
+ * Returns that {@link UserTracker} this instance was constructed with.
+ */
+ UserTracker getUserTracker();
+
+ /**
* Returns the user id for the associated {@link ContentResolver}.
*/
default int getUserId() {
@@ -53,6 +61,17 @@ public interface SettingsProxy {
}
/**
+ * Returns the actual current user handle when querying with the current user. Otherwise,
+ * returns the passed in user id.
+ */
+ default int getRealUserHandle(int userHandle) {
+ if (userHandle != UserHandle.USER_CURRENT) {
+ return userHandle;
+ }
+ return getUserTracker().getUserId();
+ }
+
+ /**
* Construct the content URI for a particular name/value pair,
* useful for monitoring changes with a ContentObserver.
* @param name to look up in the table
@@ -84,18 +103,18 @@ public interface SettingsProxy {
*
* Implicitly calls {@link #getUriFor(String)} on the passed in name.
*/
- default void registerContentObserver(String name, boolean notifyForDescendents,
+ default void registerContentObserver(String name, boolean notifyForDescendants,
ContentObserver settingsObserver) {
- registerContentObserver(getUriFor(name), notifyForDescendents, settingsObserver);
+ registerContentObserver(getUriFor(name), notifyForDescendants, settingsObserver);
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
*/
- default void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ default void registerContentObserver(Uri uri, boolean notifyForDescendants,
ContentObserver settingsObserver) {
- registerContentObserverForUser(uri, notifyForDescendents, settingsObserver, getUserId());
+ registerContentObserverForUser(uri, notifyForDescendants, settingsObserver, getUserId());
}
/**
@@ -127,10 +146,10 @@ public interface SettingsProxy {
* Implicitly calls {@link #getUriFor(String)} on the passed in name.
*/
default void registerContentObserverForUser(
- String name, boolean notifyForDescendents, ContentObserver settingsObserver,
+ String name, boolean notifyForDescendants, ContentObserver settingsObserver,
int userHandle) {
registerContentObserverForUser(
- getUriFor(name), notifyForDescendents, settingsObserver, userHandle);
+ getUriFor(name), notifyForDescendants, settingsObserver, userHandle);
}
/**
@@ -138,10 +157,10 @@ public interface SettingsProxy {
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
*/
default void registerContentObserverForUser(
- Uri uri, boolean notifyForDescendents, ContentObserver settingsObserver,
+ Uri uri, boolean notifyForDescendants, ContentObserver settingsObserver,
int userHandle) {
getContentResolver().registerContentObserver(
- uri, notifyForDescendents, settingsObserver, userHandle);
+ uri, notifyForDescendants, settingsObserver, getRealUserHandle(userHandle));
}
/** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
index 0b8257da8fb5..561495e9d092 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
@@ -19,7 +19,6 @@ package com.android.systemui.util.settings
import android.annotation.UserIdInt
import android.database.ContentObserver
-import android.os.UserHandle
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -29,8 +28,8 @@ object SettingsProxyExt {
/** Returns a flow of [Unit] that is invoked each time that content is updated. */
fun SettingsProxy.observerFlow(
+ @UserIdInt userId: Int,
vararg names: String,
- @UserIdInt userId: Int = UserHandle.USER_CURRENT,
): Flow<Unit> {
return conflatedCallbackFlow {
val observer =
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
index 0dbb76f8f758..fba7ddf5fe34 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -20,14 +20,18 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
+import com.android.systemui.settings.UserTracker;
+
import javax.inject.Inject;
class SystemSettingsImpl implements SystemSettings {
private final ContentResolver mContentResolver;
+ private final UserTracker mUserTracker;
@Inject
- SystemSettingsImpl(ContentResolver contentResolver) {
+ SystemSettingsImpl(ContentResolver contentResolver, UserTracker userTracker) {
mContentResolver = contentResolver;
+ mUserTracker = userTracker;
}
@Override
@@ -36,13 +40,19 @@ class SystemSettingsImpl implements SystemSettings {
}
@Override
+ public UserTracker getUserTracker() {
+ return mUserTracker;
+ }
+
+ @Override
public Uri getUriFor(String name) {
return Settings.System.getUriFor(name);
}
@Override
public String getStringForUser(String name, int userHandle) {
- return Settings.System.getStringForUser(mContentResolver, name, userHandle);
+ return Settings.System.getStringForUser(mContentResolver, name,
+ getRealUserHandle(userHandle));
}
@Override
@@ -52,7 +62,8 @@ class SystemSettingsImpl implements SystemSettings {
@Override
public boolean putStringForUser(String name, String value, int userHandle) {
- return Settings.System.putStringForUser(mContentResolver, name, value, userHandle);
+ return Settings.System.putStringForUser(mContentResolver, name, value,
+ getRealUserHandle(userHandle));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index f71d98827e4b..a4537267ed62 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -25,6 +25,7 @@ import android.os.Bundle;
import android.provider.Settings;
import android.view.WindowManager.LayoutParams;
+import com.android.internal.R;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
@@ -55,7 +56,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
public static final String VOLUME_UP_SILENT = "sysui_volume_up_silent";
public static final String VOLUME_SILENT_DO_NOT_DISTURB = "sysui_do_not_disturb";
- public static final boolean DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT = false;
+ private final boolean mDefaultVolumeDownToEnterSilent;
public static final boolean DEFAULT_VOLUME_UP_TO_EXIT_SILENT = false;
public static final boolean DEFAULT_DO_NOT_DISTURB_WHEN_SILENT = false;
@@ -72,12 +73,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
private final KeyguardViewMediator mKeyguardViewMediator;
private final ActivityStarter mActivityStarter;
private VolumeDialog mDialog;
- private VolumePolicy mVolumePolicy = new VolumePolicy(
- DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT, // volumeDownToEnterSilent
- DEFAULT_VOLUME_UP_TO_EXIT_SILENT, // volumeUpToExitSilent
- DEFAULT_DO_NOT_DISTURB_WHEN_SILENT, // doNotDisturbWhenSilent
- 400 // vibrateToSilentDebounce
- );
+ private VolumePolicy mVolumePolicy;
@Inject
public VolumeDialogComponent(
@@ -107,7 +103,20 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
mDialog = dialog;
mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);
}).build();
+
+
+ mDefaultVolumeDownToEnterSilent = mContext.getResources()
+ .getBoolean(R.bool.config_volume_down_to_enter_silent);
+
+ mVolumePolicy = new VolumePolicy(
+ mDefaultVolumeDownToEnterSilent, // volumeDownToEnterSilent
+ DEFAULT_VOLUME_UP_TO_EXIT_SILENT, // volumeUpToExitSilent
+ DEFAULT_DO_NOT_DISTURB_WHEN_SILENT, // doNotDisturbWhenSilent
+ 400 // vibrateToSilentDebounce
+ );
+
applyConfiguration();
+
tunerService.addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
VOLUME_SILENT_DO_NOT_DISTURB);
demoModeController.addCallback(this);
@@ -121,7 +130,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
if (VOLUME_DOWN_SILENT.equals(key)) {
volumeDownToEnterSilent =
- TunerService.parseIntegerSwitch(newValue, DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT);
+ TunerService.parseIntegerSwitch(newValue, mDefaultVolumeDownToEnterSilent);
} else if (VOLUME_UP_SILENT.equals(key)) {
volumeUpToExitSilent =
TunerService.parseIntegerSwitch(newValue, DEFAULT_VOLUME_UP_TO_EXIT_SILENT);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 98d904e60603..89b66eea7f9f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -46,7 +46,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.os.VibrationEffect;
import android.provider.Settings;
import android.service.notification.Condition;
@@ -69,6 +68,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
@@ -133,6 +133,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private final CaptioningManager mCaptioningManager;
private final KeyguardManager mKeyguardManager;
private final ActivityManager mActivityManager;
+ private final UserTracker mUserTracker;
protected C mCallbacks = new C();
private final State mState = new State();
protected final MediaSessionsCallbacks mMediaSessionsCallbacksW;
@@ -180,6 +181,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
CaptioningManager captioningManager,
KeyguardManager keyguardManager,
ActivityManager activityManager,
+ UserTracker userTracker,
DumpManager dumpManager
) {
mContext = context.getApplicationContext();
@@ -209,6 +211,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
mCaptioningManager = captioningManager;
mKeyguardManager = keyguardManager;
mActivityManager = activityManager;
+ mUserTracker = userTracker;
dumpManager.registerDumpable("VolumeDialogControllerImpl", this);
boolean accessibilityVolumeStreamActive = accessibilityManager
@@ -371,7 +374,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
if (System.currentTimeMillis() - mLastToggledRingerOn < TOUCH_FEEDBACK_TIMEOUT_MS) {
try {
mAudioService.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD,
- UserHandle.USER_CURRENT);
+ mUserTracker.getUserId());
} catch (RemoteException e) {
// ignore
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 4cbc709aadc4..4da5d499c5e7 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -273,7 +273,7 @@ public class QuickAccessWalletController {
};
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT),
+ Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
false /* notifyForDescendants */,
mDefaultPaymentAppObserver,
UserHandle.USER_ALL);
@@ -293,7 +293,7 @@ public class QuickAccessWalletController {
};
mSecureSettings.registerContentObserverForUser(
- Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
+ QuickAccessWalletClientImpl.SETTING_KEY,
false /* notifyForDescendants */,
mWalletPreferenceObserver,
UserHandle.USER_ALL);
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
new file mode 100644
index 000000000000..7b8235acb0a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallet.controller
+
+import android.Manifest
+import android.content.Context
+import android.content.IntentFilter
+import android.service.quickaccesswallet.GetWalletCardsError
+import android.service.quickaccesswallet.GetWalletCardsResponse
+import android.service.quickaccesswallet.QuickAccessWalletClient
+import android.service.quickaccesswallet.WalletCard
+import com.android.systemui.broadcast.BroadcastDispatcher
+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.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.shareIn
+
+@SysUISingleton
+class WalletContextualSuggestionsController
+@Inject
+constructor(
+ @Application private val applicationCoroutineScope: CoroutineScope,
+ private val walletController: QuickAccessWalletController,
+ broadcastDispatcher: BroadcastDispatcher,
+ featureFlags: FeatureFlags
+) {
+ private val allWalletCards: Flow<List<WalletCard>> =
+ if (featureFlags.isEnabled(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)) {
+ conflatedCallbackFlow {
+ val callback =
+ object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
+ override fun onWalletCardsRetrieved(response: GetWalletCardsResponse) {
+ trySendWithFailureLogging(response.walletCards, TAG)
+ }
+
+ override fun onWalletCardRetrievalError(error: GetWalletCardsError) {
+ trySendWithFailureLogging(emptyList<WalletCard>(), TAG)
+ }
+ }
+
+ walletController.setupWalletChangeObservers(
+ callback,
+ QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ )
+ walletController.updateWalletPreference()
+ walletController.queryWalletCards(callback)
+
+ awaitClose {
+ walletController.unregisterWalletChangeObservers(
+ QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ )
+ }
+ }
+ } else {
+ emptyFlow()
+ }
+
+ private val contextualSuggestionsCardIds: Flow<Set<String>> =
+ if (featureFlags.isEnabled(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)) {
+ broadcastDispatcher.broadcastFlow(
+ filter = IntentFilter(ACTION_UPDATE_WALLET_CONTEXTUAL_SUGGESTIONS),
+ permission = Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE,
+ flags = Context.RECEIVER_EXPORTED
+ ) { intent, _ ->
+ if (intent.hasExtra(UPDATE_CARD_IDS_EXTRA)) {
+ intent.getStringArrayListExtra(UPDATE_CARD_IDS_EXTRA).toSet()
+ } else {
+ emptySet()
+ }
+ }
+ } else {
+ emptyFlow()
+ }
+
+ val contextualSuggestionCards: Flow<List<WalletCard>> =
+ combine(allWalletCards, contextualSuggestionsCardIds) { cards, ids ->
+ cards.filter { card -> ids.contains(card.cardId) }
+ }
+ .shareIn(applicationCoroutineScope, replay = 1, started = SharingStarted.Eagerly)
+
+ companion object {
+ private const val ACTION_UPDATE_WALLET_CONTEXTUAL_SUGGESTIONS =
+ "com.android.systemui.wallet.UPDATE_CONTEXTUAL_SUGGESTIONS"
+
+ private const val UPDATE_CARD_IDS_EXTRA = "cardIds"
+
+ private const val TAG = "WalletSuggestions"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 1f1b32c1c63a..8b925b7ad312 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -26,7 +26,6 @@ import android.graphics.RectF;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Trace;
-import android.os.UserHandle;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.Surface;
@@ -37,6 +36,7 @@ import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.FileDescriptor;
@@ -58,6 +58,8 @@ public class ImageWallpaper extends WallpaperService {
private volatile int mPages = 1;
private boolean mPagesComputed = false;
+ private final UserTracker mUserTracker;
+
// used for most tasks (call canvas.drawBitmap, load/unload the bitmap)
@Background
private final DelayableExecutor mBackgroundExecutor;
@@ -66,9 +68,11 @@ public class ImageWallpaper extends WallpaperService {
private static final int DELAY_UNLOAD_BITMAP = 2000;
@Inject
- public ImageWallpaper(@Background DelayableExecutor backgroundExecutor) {
+ public ImageWallpaper(@Background DelayableExecutor backgroundExecutor,
+ UserTracker userTracker) {
super();
mBackgroundExecutor = backgroundExecutor;
+ mUserTracker = userTracker;
}
@Override
@@ -288,7 +292,7 @@ public class ImageWallpaper extends WallpaperService {
boolean loadSuccess = false;
Bitmap bitmap;
try {
- bitmap = mWallpaperManager.getBitmapAsUser(UserHandle.USER_CURRENT, false);
+ bitmap = mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
if (bitmap != null
&& bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
throw new RuntimeException("Wallpaper is too large to draw!");
@@ -300,9 +304,9 @@ public class ImageWallpaper extends WallpaperService {
// default wallpaper can't be loaded.
Log.w(TAG, "Unable to load wallpaper!", exception);
mWallpaperManager.clearWallpaper(
- WallpaperManager.FLAG_SYSTEM, UserHandle.USER_CURRENT);
+ WallpaperManager.FLAG_SYSTEM, mUserTracker.getUserId());
try {
- bitmap = mWallpaperManager.getBitmapAsUser(UserHandle.USER_CURRENT, false);
+ bitmap = mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
} catch (RuntimeException | OutOfMemoryError e) {
Log.w(TAG, "Unable to load default wallpaper!", e);
bitmap = null;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 9a9acf3dd986..a4180fd2e0f1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -29,7 +29,6 @@ import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -275,7 +274,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
ArgumentCaptor<ContentObserver> observerCaptor =
ArgumentCaptor.forClass(ContentObserver.class);
mController.init();
- verify(mSecureSettings).registerContentObserverForUser(any(Uri.class),
+ verify(mSecureSettings).registerContentObserverForUser(any(String.class),
anyBoolean(), observerCaptor.capture(), eq(UserHandle.USER_ALL));
ContentObserver observer = observerCaptor.getValue();
mExecutor.runAllReady();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index 84f6d913b310..075ef9df9664 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -405,6 +405,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
}
@Test
+ public void onBouncerVisibilityChanged_resetsScale() {
+ mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE);
+
+ verify(mView).resetScale();
+ }
+
+ @Test
public void onStartingToHide_sideFpsHintShown_sideFpsHintHidden() {
setupGetSecurityView();
setupConditionsToEnableSideFpsHint();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 36ed669e299c..1bbc19931c21 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -49,6 +49,8 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
+import android.window.BackEvent;
+import android.window.OnBackAnimationCallback;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.test.filters.SmallTest;
@@ -357,6 +359,27 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
assertThat(viewFlipperConstraint.layout.leftToLeft).isEqualTo(PARENT_ID);
}
+ @Test
+ public void testPlayBackAnimation() {
+ OnBackAnimationCallback backCallback = mKeyguardSecurityContainer.getBackCallback();
+ backCallback.onBackStarted(createBackEvent(0, 0));
+ mKeyguardSecurityContainer.getBackCallback().onBackProgressed(
+ createBackEvent(0, 1));
+ assertThat(mKeyguardSecurityContainer.getScaleX()).isEqualTo(
+ KeyguardSecurityContainer.MIN_BACK_SCALE);
+ assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(
+ KeyguardSecurityContainer.MIN_BACK_SCALE);
+
+ // reset scale
+ mKeyguardSecurityContainer.resetScale();
+ assertThat(mKeyguardSecurityContainer.getScaleX()).isEqualTo(1);
+ assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1);
+ }
+
+ private BackEvent createBackEvent(float touchX, float progress) {
+ return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
+ }
+
private Configuration configuration(@Configuration.Orientation int orientation) {
Configuration config = new Configuration();
config.orientation = orientation;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java
index 7aa47632965f..4a5c1bed7b44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java
@@ -22,14 +22,16 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-import android.os.UserHandle;
+import android.app.ActivityManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import org.junit.Before;
import org.junit.Rule;
@@ -42,11 +44,14 @@ import org.mockito.junit.MockitoRule;
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
+ private static final int MY_USER_ID = ActivityManager.getCurrentUser();
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@Mock
+ private UserTracker mUserTracker;
+ @Mock
private AccessibilityButtonModeObserver.ModeChangedListener mListener;
private AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
@@ -56,10 +61,12 @@ public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
@Before
public void setUp() {
+ when(mUserTracker.getUserId()).thenReturn(MY_USER_ID);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
- mAccessibilityButtonModeObserver = new AccessibilityButtonModeObserver(mContext);
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, MY_USER_ID);
+ mAccessibilityButtonModeObserver = new AccessibilityButtonModeObserver(mContext,
+ mUserTracker);
}
@Test
@@ -67,7 +74,7 @@ public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
mAccessibilityButtonModeObserver.addListener(mListener);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE,
- UserHandle.USER_CURRENT);
+ MY_USER_ID);
mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
@@ -80,7 +87,7 @@ public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
mAccessibilityButtonModeObserver.removeListener(mListener);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE,
- UserHandle.USER_CURRENT);
+ MY_USER_ID);
mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
@@ -91,7 +98,7 @@ public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
public void getCurrentAccessibilityButtonMode_expectedValue() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE,
- UserHandle.USER_CURRENT);
+ MY_USER_ID);
final int actualValue =
mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java
index 4145437a71b2..a5a7a4a09227 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java
@@ -21,14 +21,16 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-import android.os.UserHandle;
+import android.app.ActivityManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import org.junit.Before;
import org.junit.Rule;
@@ -42,11 +44,14 @@ import org.mockito.junit.MockitoRule;
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class AccessibilityButtonTargetsObserverTest extends SysuiTestCase {
+ private static final int MY_USER_ID = ActivityManager.getCurrentUser();
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@Mock
+ private UserTracker mUserTracker;
+ @Mock
private AccessibilityButtonTargetsObserver.TargetsChangedListener mListener;
private AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
@@ -55,7 +60,9 @@ public class AccessibilityButtonTargetsObserverTest extends SysuiTestCase {
@Before
public void setUp() {
- mAccessibilityButtonTargetsObserver = new AccessibilityButtonTargetsObserver(mContext);
+ when(mUserTracker.getUserId()).thenReturn(MY_USER_ID);
+ mAccessibilityButtonTargetsObserver = new AccessibilityButtonTargetsObserver(mContext,
+ mUserTracker);
}
@Test
@@ -63,7 +70,7 @@ public class AccessibilityButtonTargetsObserverTest extends SysuiTestCase {
mAccessibilityButtonTargetsObserver.addListener(mListener);
Settings.Secure.putStringForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
- UserHandle.USER_CURRENT);
+ MY_USER_ID);
mAccessibilityButtonTargetsObserver.mContentObserver.onChange(false);
@@ -76,7 +83,7 @@ public class AccessibilityButtonTargetsObserverTest extends SysuiTestCase {
mAccessibilityButtonTargetsObserver.removeListener(mListener);
Settings.Secure.putStringForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
- UserHandle.USER_CURRENT);
+ MY_USER_ID);
mAccessibilityButtonTargetsObserver.mContentObserver.onChange(false);
@@ -87,7 +94,7 @@ public class AccessibilityButtonTargetsObserverTest extends SysuiTestCase {
public void getCurrentAccessibilityButtonTargets_expectedValue() {
Settings.Secure.putStringForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
- UserHandle.USER_CURRENT);
+ MY_USER_ID);
final String actualValue =
mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java
index 41fd2b3a40e0..9c601a8670c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java
@@ -18,18 +18,20 @@ package com.android.systemui.accessibility;
import static com.google.common.truth.Truth.assertThat;
+import android.app.ActivityManager;
import android.content.Context;
-import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
/** Test for {@link SecureSettingsContentObserver}. */
@RunWith(AndroidTestingRunner.class)
@@ -40,7 +42,9 @@ public class SecureSettingsContentObserverTest extends SysuiTestCase {
@Before
public void setUpObserver() {
- mTestObserver = new FakeSecureSettingsContentObserver(mContext,
+ UserTracker userTracker = Mockito.mock(UserTracker.class);
+ Mockito.when(userTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
+ mTestObserver = new FakeSecureSettingsContentObserver(mContext, userTracker,
Settings.Secure.ACCESSIBILITY_BUTTON_MODE);
}
@@ -57,7 +61,7 @@ public class SecureSettingsContentObserverTest extends SysuiTestCase {
@Test
public void checkValue() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 1, UserHandle.USER_CURRENT);
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 1, ActivityManager.getCurrentUser());
assertThat(mTestObserver.getSettingsValue()).isEqualTo("1");
}
@@ -66,9 +70,9 @@ public class SecureSettingsContentObserverTest extends SysuiTestCase {
private static class FakeSecureSettingsContentObserver extends
SecureSettingsContentObserver<Object> {
- protected FakeSecureSettingsContentObserver(Context context,
+ protected FakeSecureSettingsContentObserver(Context context, UserTracker userTracker,
String secureSettingsKey) {
- super(context, secureSettingsKey);
+ super(context, userTracker, secureSettingsKey);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index b7d345965d36..cdf3f654899e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -32,8 +32,11 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.AdditionalAnswers.returnsSecondArg;
import static org.mockito.ArgumentMatchers.any;
+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;
@@ -76,6 +79,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.model.SysUiState;
import com.android.systemui.util.leak.ReferenceTestUtils;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.utils.os.FakeHandler;
import org.junit.After;
@@ -111,6 +115,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
IRemoteMagnificationAnimationCallback mAnimationCallback;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ @Mock
+ private SecureSettings mSecureSettings;
private Handler mHandler;
private TestableWindowManager mWindowManager;
@@ -138,6 +144,10 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
}).when(mSfVsyncFrameProvider).postFrameCallback(
any(FrameCallback.class));
mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class));
+ when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).then(
+ returnsSecondArg());
+ when(mSecureSettings.getFloatForUser(anyString(), anyFloat(), anyInt())).then(
+ returnsSecondArg());
mResources = getContext().getOrCreateTestableResources().getResources();
mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 8ca17b974100..f34a36f68744 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.UserHandle;
@@ -40,6 +41,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import com.android.systemui.util.settings.SecureSettings;
import org.junit.After;
import org.junit.Before;
@@ -48,6 +50,8 @@ 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;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -71,8 +75,12 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor;
private KeyguardUpdateMonitorCallback mKeyguardCallback;
+ @Mock
+ private SecureSettings mSecureSettings;
+
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mContextWrapper = new ContextWrapper(mContext) {
@Override
public Context createContextAsUser(UserHandle user, int flags) {
@@ -128,7 +136,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onKeyguardVisibilityChanged_showing_destroyWidget() {
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper, mSecureSettings);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
@@ -154,7 +162,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
final int fakeUserId = 1;
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper, mSecureSettings);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserSwitching(fakeUserId);
@@ -167,7 +175,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
final int fakeUserId = 1;
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper, mSecureSettings);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
mKeyguardCallback.onKeyguardVisibilityChanged(true);
@@ -197,7 +205,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onAccessibilityButtonModeChanged_floatingModeAndHasButtonTargets_showWidget() {
Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
- UserHandle.USER_CURRENT);
+ ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
@@ -208,7 +216,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonModeChanged_floatingModeAndNoButtonTargets_destroyWidget() {
Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT);
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
@@ -220,7 +228,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onAccessibilityButtonModeChanged_navBarModeAndHasButtonTargets_destroyWidget() {
Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
- UserHandle.USER_CURRENT);
+ ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
@@ -231,7 +239,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonModeChanged_navBarModeAndNoButtonTargets_destroyWidget() {
Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT);
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
@@ -243,7 +251,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onAccessibilityButtonTargetsChanged_floatingModeAndHasButtonTargets_showWidget() {
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
- UserHandle.USER_CURRENT);
+ ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS);
@@ -255,7 +263,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onAccessibilityButtonTargetsChanged_floatingModeAndNoButtonTargets_destroyWidget() {
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
- UserHandle.USER_CURRENT);
+ ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonTargetsChanged("");
@@ -267,7 +275,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onAccessibilityButtonTargetsChanged_navBarModeAndHasButtonTargets_destroyWidget() {
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS);
@@ -279,7 +287,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onAccessibilityButtonTargetsChanged_navBarModeAndNoButtonTargets_destroyWidget() {
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, ActivityManager.getCurrentUser());
mController = setUpController();
mController.onAccessibilityButtonTargetsChanged("");
@@ -293,7 +301,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
final AccessibilityFloatingMenuController controller =
new AccessibilityFloatingMenuController(mContextWrapper, mTargetsObserver,
- mModeObserver, mKeyguardUpdateMonitor);
+ mModeObserver, mKeyguardUpdateMonitor, mSecureSettings);
controller.init();
return controller;
@@ -302,10 +310,10 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
private void enableAccessibilityFloatingMenuConfig() {
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
- UserHandle.USER_CURRENT);
+ ActivityManager.getCurrentUser());
Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
- UserHandle.USER_CURRENT);
+ ActivityManager.getCurrentUser());
}
private void captureKeyguardUpdateMonitorCallback() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
index 558261b31eb2..04345fdf2893 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
@@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.settings.SecureSettings;
import org.junit.After;
import org.junit.Before;
@@ -55,6 +56,8 @@ public class AccessibilityFloatingMenuTest extends SysuiTestCase {
@Mock
private AccessibilityManager mAccessibilityManager;
+ @Mock
+ private SecureSettings mSecureSettings;
private AccessibilityFloatingMenuView mMenuView;
private AccessibilityFloatingMenu mMenu;
@@ -69,7 +72,7 @@ public class AccessibilityFloatingMenuTest extends SysuiTestCase {
final Position position = new Position(0, 0);
mMenuView = new AccessibilityFloatingMenuView(mContext, position);
- mMenu = new AccessibilityFloatingMenu(mContext, mMenuView);
+ mMenu = new AccessibilityFloatingMenu(mContext, mSecureSettings, mMenuView);
}
@Test
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 3c40835fe59d..b92c5d039d45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -53,6 +53,7 @@ import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.SysuiTestableContext
import com.android.systemui.dump.DumpManager
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.FakeExecutor
@@ -106,8 +107,7 @@ class SideFpsControllerTest : SysuiTestCase() {
enum class DeviceConfig {
X_ALIGNED,
- Y_ALIGNED_UNFOLDED,
- Y_ALIGNED_FOLDED
+ Y_ALIGNED,
}
private lateinit var deviceConfig: DeviceConfig
@@ -143,6 +143,7 @@ class SideFpsControllerTest : SysuiTestCase() {
private fun testWithDisplay(
deviceConfig: DeviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation: Boolean = false,
initInfo: DisplayInfo.() -> Unit = {},
windowInsets: WindowInsets = insetsForSmallNavbar(),
block: () -> Unit
@@ -151,27 +152,21 @@ class SideFpsControllerTest : SysuiTestCase() {
when (deviceConfig) {
DeviceConfig.X_ALIGNED -> {
- displayWidth = 2560
- displayHeight = 1600
- sensorLocation = SensorLocationInternal("", 2325, 0, 0)
- boundsWidth = 160
- boundsHeight = 84
+ displayWidth = 3000
+ displayHeight = 1500
+ sensorLocation = SensorLocationInternal("", 2500, 0, 0)
+ boundsWidth = 200
+ boundsHeight = 100
}
- DeviceConfig.Y_ALIGNED_UNFOLDED -> {
- displayWidth = 2208
- displayHeight = 1840
- sensorLocation = SensorLocationInternal("", 0, 510, 0)
- boundsWidth = 110
- boundsHeight = 210
- }
- DeviceConfig.Y_ALIGNED_FOLDED -> {
- displayWidth = 1080
- displayHeight = 2100
- sensorLocation = SensorLocationInternal("", 0, 590, 0)
- boundsWidth = 110
- boundsHeight = 210
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ sensorLocation = SensorLocationInternal("", 0, 300, 0)
+ boundsWidth = 100
+ boundsHeight = 200
}
}
+
indicatorBounds = Rect(0, 0, boundsWidth, boundsHeight)
displayBounds = Rect(0, 0, displayWidth, displayHeight)
var locations = listOf(sensorLocation)
@@ -194,8 +189,10 @@ class SideFpsControllerTest : SysuiTestCase() {
val displayInfo = DisplayInfo()
displayInfo.initInfo()
+
val dmGlobal = mock(DisplayManagerGlobal::class.java)
val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS)
+
whenEver(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo)
whenEver(windowManager.defaultDisplay).thenReturn(display)
whenEver(windowManager.maximumWindowMetrics)
@@ -203,9 +200,15 @@ class SideFpsControllerTest : SysuiTestCase() {
whenEver(windowManager.currentWindowMetrics)
.thenReturn(WindowMetrics(displayBounds, windowInsets))
+ val sideFpsControllerContext = context.createDisplayContext(display) as SysuiTestableContext
+ sideFpsControllerContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_reverseDefaultRotation,
+ isReverseDefaultRotation
+ )
+
sideFpsController =
SideFpsController(
- context.createDisplayContext(display),
+ sideFpsControllerContext,
layoutInflater,
fingerprintManager,
windowManager,
@@ -299,108 +302,316 @@ class SideFpsControllerTest : SysuiTestCase() {
}
@Test
- fun showsWithTaskbar() =
- testWithDisplay(deviceConfig = DeviceConfig.X_ALIGNED, { rotation = Surface.ROTATION_0 }) {
- hidesWithTaskbar(visible = true)
- }
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_0() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_0 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun showsWithTaskbarOnY() =
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_90() =
testWithDisplay(
- deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
- { rotation = Surface.ROTATION_0 }
- ) { hidesWithTaskbar(visible = true) }
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_90 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun showsWithTaskbar90() =
- testWithDisplay(deviceConfig = DeviceConfig.X_ALIGNED, { rotation = Surface.ROTATION_90 }) {
- hidesWithTaskbar(visible = true)
- }
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_180() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_180 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarCollapsedDownForXAlignedSensor_180() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_180 },
+ windowInsets = insetsForSmallNavbar()
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun showsWithTaskbar90OnY() =
+ fun hidesSfpsIndicatorWhenOccludingTaskbarForXAlignedSensor_180() =
testWithDisplay(
- deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_180 },
+ windowInsets = insetsForLargeNavbar()
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_270() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_270 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_0() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_0 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_90() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_90 }
- ) { hidesWithTaskbar(visible = true) }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun showsWithTaskbar180() =
+ fun showsSfpsIndicatorWithTaskbarCollapsedDownForXAlignedSensor_InReverseDefaultRotation_90() =
testWithDisplay(
deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_90 },
+ windowInsets = insetsForSmallNavbar()
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun hidesSfpsIndicatorWhenOccludingTaskbarForXAlignedSensor_InReverseDefaultRotation_90() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_90 },
+ windowInsets = insetsForLargeNavbar()
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_180() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_180 }
- ) { hidesWithTaskbar(visible = true) }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun showsWithTaskbar270OnY() =
+ fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_270() =
testWithDisplay(
- deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_270 }
- ) { hidesWithTaskbar(visible = true) }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun showsWithTaskbarCollapsedDown() =
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_0() =
testWithDisplay(
- deviceConfig = DeviceConfig.X_ALIGNED,
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_0 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_90() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_90 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_180() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_180 },
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_270() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_270 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarCollapsedDownForYAlignedSensor_270() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_270 },
windowInsets = insetsForSmallNavbar()
- ) { hidesWithTaskbar(visible = true) }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun showsWithTaskbarCollapsedDownOnY() =
+ fun hidesSfpsIndicatorWhenOccludingTaskbarForYAlignedSensor_270() =
testWithDisplay(
- deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_270 },
+ windowInsets = insetsForLargeNavbar()
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_0() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_0 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_90() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_90 },
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_180() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_180 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+
+ @Test
+ fun showsSfpsIndicatorWithTaskbarCollapsedDownForYAlignedSensor_InReverseDefaultRotation_180() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_180 },
windowInsets = insetsForSmallNavbar()
- ) { hidesWithTaskbar(visible = true) }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
@Test
- fun hidesWithTaskbarDown() =
+ fun hidesSfpsIndicatorWhenOccludingTaskbarForYAlignedSensor_InReverseDefaultRotation_180() =
testWithDisplay(
- deviceConfig = DeviceConfig.X_ALIGNED,
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_180 },
windowInsets = insetsForLargeNavbar()
- ) { hidesWithTaskbar(visible = false) }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
@Test
- fun hidesWithTaskbarDownOnY() =
+ fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_270() =
testWithDisplay(
- deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
- { rotation = Surface.ROTATION_270 },
- windowInsets = insetsForLargeNavbar()
- ) { hidesWithTaskbar(visible = true) }
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_270 }
+ ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
- private fun hidesWithTaskbar(visible: Boolean) {
+ private fun verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible: Boolean) {
+ sideFpsController.overlayOffsets = sensorLocation
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
- sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(visible, false)
+ sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(true, false)
executor.runAllReady()
verify(windowManager).addView(any(), any())
verify(windowManager, never()).removeView(any())
- verify(sideFpsView).visibility = if (visible) View.VISIBLE else View.GONE
+ verify(sideFpsView).visibility = if (sfpsViewVisible) View.VISIBLE else View.GONE
}
+ /**
+ * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_0,
+ * and uses RotateUtils.rotateBounds to map to the correct indicator location given the device
+ * rotation. Assuming RotationUtils.rotateBounds works correctly, tests for indicator placement
+ * in other rotations have been omitted.
+ */
@Test
- fun testIndicatorPlacementForXAlignedSensor() =
- testWithDisplay(deviceConfig = DeviceConfig.X_ALIGNED) {
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+ fun verifiesIndicatorPlacementForXAlignedSensor_0() {
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_0 }
+ ) {
sideFpsController.overlayOffsets = sensorLocation
+
sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
+
+ overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
+ assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
+ assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
+ }
+ }
+ /**
+ * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_270
+ * in reverse default rotation. It then uses RotateUtils.rotateBounds to map to the correct
+ * indicator location given the device rotation. Assuming RotationUtils.rotateBounds works
+ * correctly, tests for indicator placement in other rotations have been omitted.
+ */
+ @Test
+ fun verifiesIndicatorPlacementForXAlignedSensor_InReverseDefaultRotation_270() {
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_270 }
+ ) {
+ sideFpsController.overlayOffsets = sensorLocation
+
+ sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
+
+ overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+ executor.runAllReady()
+
+ verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
}
+ }
+ /**
+ * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_0,
+ * and uses RotateUtils.rotateBounds to map to the correct indicator location given the device
+ * rotation. Assuming RotationUtils.rotateBounds works correctly, tests for indicator placement
+ * in other rotations have been omitted.
+ */
@Test
- fun testIndicatorPlacementForYAlignedSensor() =
- testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
+ fun verifiesIndicatorPlacementForYAlignedSensor_0() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_0 }
+ ) {
sideFpsController.overlayOffsets = sensorLocation
+
sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
+
+ overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+ executor.runAllReady()
+
+ verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
+ assertThat(overlayViewParamsCaptor.value.x).isEqualTo(displayWidth - boundsWidth)
+ assertThat(overlayViewParamsCaptor.value.y).isEqualTo(sensorLocation.sensorLocationY)
+ }
+
+ /**
+ * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_270
+ * in reverse default rotation. It then uses RotateUtils.rotateBounds to map to the correct
+ * indicator location given the device rotation. Assuming RotationUtils.rotateBounds works
+ * correctly, tests for indicator placement in other rotations have been omitted.
+ */
+ @Test
+ fun verifiesIndicatorPlacementForYAlignedSensor_InReverseDefaultRotation_270() =
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_270 }
+ ) {
+ sideFpsController.overlayOffsets = sensorLocation
+
+ sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
+
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -412,7 +623,6 @@ class SideFpsControllerTest : SysuiTestCase() {
@Test
fun hasSideFpsSensor_withSensorProps_returnsTrue() = testWithDisplay {
// By default all those tests assume the side fps sensor is available.
-
assertThat(fingerprintManager.hasSideFpsSensor()).isTrue()
}
@@ -425,7 +635,7 @@ class SideFpsControllerTest : SysuiTestCase() {
@Test
fun testLayoutParams_isKeyguardDialogType() =
- testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
+ testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED) {
sideFpsController.overlayOffsets = sensorLocation
sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
@@ -440,7 +650,7 @@ class SideFpsControllerTest : SysuiTestCase() {
@Test
fun testLayoutParams_hasNoMoveAnimationWindowFlag() =
- testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
+ testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED) {
sideFpsController.overlayOffsets = sensorLocation
sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
@@ -455,7 +665,7 @@ class SideFpsControllerTest : SysuiTestCase() {
@Test
fun testLayoutParams_hasTrustedOverlayWindowFlag() =
- testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
+ testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED) {
sideFpsController.overlayOffsets = sensorLocation
sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 1ef119d7fb16..0690d1bc77af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -99,6 +100,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
@Mock private lateinit var unlockedScreenOffAnimationController:
UnlockedScreenOffAnimationController
@Mock private lateinit var udfpsDisplayMode: UdfpsDisplayModeProvider
+ @Mock private lateinit var secureSettings: SecureSettings
@Mock private lateinit var controllerCallback: IUdfpsOverlayControllerCallback
@Mock private lateinit var udfpsController: UdfpsController
@Mock private lateinit var udfpsView: UdfpsView
@@ -139,8 +141,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
statusBarStateController, shadeExpansionStateManager, statusBarKeyguardViewManager,
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
configurationController, keyguardStateController,
- unlockedScreenOffAnimationController, udfpsDisplayMode, REQUEST_ID, reason,
- controllerCallback, onTouch, activityLaunchAnimator, featureFlags,
+ unlockedScreenOffAnimationController, udfpsDisplayMode, secureSettings, REQUEST_ID,
+ reason, controllerCallback, onTouch, activityLaunchAnimator, featureFlags,
primaryBouncerInteractor, alternateBouncerInteractor, isDebuggable,
)
block()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 0c34e54d2ec4..232daadce8e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -96,6 +96,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.Execution;
import com.android.systemui.util.concurrency.FakeExecution;
import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.time.SystemClock;
@@ -205,6 +206,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
@Mock
private AlternateBouncerInteractor mAlternateBouncerInteractor;
+ @Mock
+ private SecureSettings mSecureSettings;
// Capture listeners so that they can be used to send events
@Captor
@@ -296,7 +299,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker,
mActivityLaunchAnimator, alternateTouchProvider, mBiometricExecutor,
mPrimaryBouncerInteractor, mSinglePointerTouchProcessor,
- mAlternateBouncerInteractor);
+ mAlternateBouncerInteractor, mSecureSettings);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 813eeeb557b8..7715f7fc5dc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -32,9 +32,9 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,9 +46,9 @@ import org.mockito.Captor;
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
- private @Captor ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback>
+ private @Captor ArgumentCaptor<PrimaryBouncerExpansionCallback>
mBouncerExpansionCallbackCaptor;
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
+ private PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
@Override
public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
index 262b4b889f84..80c3e5eaff15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
@@ -28,6 +28,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -69,6 +70,8 @@ class CameraGestureHelperTest : SysuiTestCase() {
lateinit var cameraIntents: CameraIntentsWrapper
@Mock
lateinit var contentResolver: ContentResolver
+ @Mock
+ lateinit var userTracker: UserTracker
private lateinit var underTest: CameraGestureHelper
@@ -96,6 +99,7 @@ class CameraGestureHelperTest : SysuiTestCase() {
cameraIntents = cameraIntents,
contentResolver = contentResolver,
uiExecutor = MoreExecutors.directExecutor(),
+ userTracker = userTracker,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
index d1597149ce0b..d6cafcb6b5ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
@@ -16,18 +16,23 @@
package com.android.systemui.charging
+import android.graphics.Rect
import android.testing.AndroidTestingRunner
+import android.view.Surface
import android.view.View
import android.view.WindowManager
+import android.view.WindowMetrics
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.surfaceeffects.ripple.RippleView
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.surfaceeffects.ripple.RippleView
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
@@ -35,12 +40,12 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -54,6 +59,7 @@ class WiredChargingRippleControllerTest : SysuiTestCase() {
@Mock private lateinit var rippleView: RippleView
@Mock private lateinit var windowManager: WindowManager
@Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var windowMetrics: WindowMetrics
private val systemClock = FakeSystemClock()
@Before
@@ -66,6 +72,9 @@ class WiredChargingRippleControllerTest : SysuiTestCase() {
rippleView.setupShader()
controller.rippleView = rippleView // Replace the real ripple view with a mock instance
controller.registerCallbacks()
+
+ `when`(windowMetrics.bounds).thenReturn(Rect(0, 0, 100, 100))
+ `when`(windowManager.currentWindowMetrics).thenReturn(windowMetrics)
}
@Test
@@ -164,4 +173,63 @@ class WiredChargingRippleControllerTest : SysuiTestCase() {
verify(rippleView, never()).addOnAttachStateChangeListener(attachListenerCaptor.capture())
verify(windowManager, never()).addView(eq(rippleView), any<WindowManager.LayoutParams>())
}
+
+ @Test
+ fun testRipple_layoutsCorrectly() {
+ // Sets the correct ripple size.
+ val width = 100
+ val height = 200
+ whenever(windowMetrics.bounds).thenReturn(Rect(0, 0, width, height))
+
+ // Trigger ripple.
+ val captor = ArgumentCaptor
+ .forClass(BatteryController.BatteryStateChangeCallback::class.java)
+ verify(batteryController).addCallback(captor.capture())
+
+ captor.value.onBatteryLevelChanged(
+ /* unusedBatteryLevel= */ 0,
+ /* plugged in= */ true,
+ /* charging= */ false)
+
+ val attachListenerCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
+ verify(rippleView).addOnAttachStateChangeListener(attachListenerCaptor.capture())
+ verify(windowManager).addView(eq(rippleView), any<WindowManager.LayoutParams>())
+
+ val runnableCaptor =
+ ArgumentCaptor.forClass(Runnable::class.java)
+ attachListenerCaptor.value.onViewAttachedToWindow(rippleView)
+ verify(rippleView).startRipple(runnableCaptor.capture())
+
+ // Verify size and center position.
+ val maxSize = 400f // Double the max value between width and height.
+ verify(rippleView).setMaxSize(maxWidth = maxSize, maxHeight = maxSize)
+
+ val normalizedPortPosX =
+ context.resources.getFloat(R.dimen.physical_charger_port_location_normalized_x)
+ val normalizedPortPosY =
+ context.resources.getFloat(R.dimen.physical_charger_port_location_normalized_y)
+ val expectedCenterX: Float
+ val expectedCenterY: Float
+ when (context.display.rotation) {
+ Surface.ROTATION_90 -> {
+ expectedCenterX = width * normalizedPortPosY
+ expectedCenterY = height * (1 - normalizedPortPosX)
+ }
+ Surface.ROTATION_180 -> {
+ expectedCenterX = width * (1 - normalizedPortPosX)
+ expectedCenterY = height * (1 - normalizedPortPosY)
+ }
+ Surface.ROTATION_270 -> {
+ expectedCenterX = width * (1 - normalizedPortPosY)
+ expectedCenterY = height * normalizedPortPosX
+ }
+ else -> { // Surface.ROTATION_0
+ expectedCenterX = width * normalizedPortPosX
+ expectedCenterY = height * normalizedPortPosY
+ }
+ }
+
+ verify(rippleView).setCenter(expectedCenterX, expectedCenterY)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 5c2b153bf452..af027e871542 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -36,6 +37,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.doze.DozeMachine.State;
+import com.android.systemui.settings.UserTracker;
import org.junit.Before;
import org.junit.Test;
@@ -48,6 +50,7 @@ import org.mockito.MockitoAnnotations;
@RunWithLooper
public class DozeDockHandlerTest extends SysuiTestCase {
@Mock private DozeMachine mMachine;
+ @Mock private UserTracker mUserTracker;
private AmbientDisplayConfiguration mConfig;
private DockManagerFake mDockManagerFake;
private DozeDockHandler mDockHandler;
@@ -57,9 +60,10 @@ public class DozeDockHandlerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mConfig = DozeConfigurationUtil.createMockConfig();
mDockManagerFake = spy(new DockManagerFake());
- mDockHandler = new DozeDockHandler(mConfig, mDockManagerFake);
+ mDockHandler = new DozeDockHandler(mConfig, mDockManagerFake, mUserTracker);
mDockHandler.setDozeMachine(mMachine);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
when(mMachine.getState()).thenReturn(State.DOZE_AOD);
doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 5bbd8109d8f9..a636b7f43648 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -45,6 +45,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.testing.AndroidTestingRunner;
@@ -57,6 +58,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -85,6 +87,8 @@ public class DozeMachineTest extends SysuiTestCase {
private DozeMachine.Part mPartMock;
@Mock
private DozeMachine.Part mAnotherPartMock;
+ @Mock
+ private UserTracker mUserTracker;
private DozeServiceFake mServiceFake;
private WakeLockFake mWakeLockFake;
private AmbientDisplayConfiguration mAmbientDisplayConfigMock;
@@ -97,6 +101,7 @@ public class DozeMachineTest extends SysuiTestCase {
mAmbientDisplayConfigMock = mock(AmbientDisplayConfiguration.class);
when(mDockManager.isDocked()).thenReturn(false);
when(mDockManager.isHidden()).thenReturn(false);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
mMachine = new DozeMachine(mServiceFake,
mAmbientDisplayConfigMock,
@@ -105,7 +110,8 @@ public class DozeMachineTest extends SysuiTestCase {
mDozeLog,
mDockManager,
mHost,
- new DozeMachine.Part[]{mPartMock, mAnotherPartMock});
+ new DozeMachine.Part[]{mPartMock, mAnotherPartMock},
+ mUserTracker);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 03827dab0c96..3af444a789c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -34,6 +34,7 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.reset;
@@ -57,6 +58,7 @@ import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.concurrency.FakeThreadFactory;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.FakeSensorManager;
+import com.android.systemui.util.settings.SystemSettings;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
@@ -94,6 +96,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
DevicePostureController mDevicePostureController;
@Mock
DozeLog mDozeLog;
+ @Mock
+ SystemSettings mSystemSettings;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor);
@@ -102,9 +106,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- Settings.System.putIntForUser(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, DEFAULT_BRIGHTNESS,
- UserHandle.USER_CURRENT);
+ when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS), anyInt(),
+ eq(UserHandle.USER_CURRENT))).thenReturn(DEFAULT_BRIGHTNESS);
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
@@ -131,7 +134,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mWakefulnessLifecycle,
mDozeParameters,
mDevicePostureController,
- mDozeLog);
+ mDozeLog,
+ mSystemSettings);
}
@Test
@@ -157,11 +161,10 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
}
@Test
- public void testAod_usesLightSensorRespectingUserSetting() throws Exception {
+ public void testAod_usesLightSensorRespectingUserSetting() {
int maxBrightness = 3;
- Settings.System.putIntForUser(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, maxBrightness,
- UserHandle.USER_CURRENT);
+ when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS), anyInt(),
+ eq(UserHandle.USER_CURRENT))).thenReturn(maxBrightness);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
assertEquals(maxBrightness, mServiceFake.screenBrightness);
@@ -238,7 +241,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mWakefulnessLifecycle,
mDozeParameters,
mDevicePostureController,
- mDozeLog);
+ mDozeLog,
+ mSystemSettings);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE);
reset(mDozeHost);
@@ -275,7 +279,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mWakefulnessLifecycle,
mDozeParameters,
mDevicePostureController,
- mDozeLog);
+ mDozeLog,
+ mSystemSettings);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
@@ -306,7 +311,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mWakefulnessLifecycle,
mDozeParameters,
mDevicePostureController,
- mDozeLog);
+ mDozeLog,
+ mSystemSettings);
// GIVEN the device is in AOD
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
@@ -344,7 +350,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mWakefulnessLifecycle,
mDozeParameters,
mDevicePostureController,
- mDozeLog);
+ mDozeLog,
+ mSystemSettings);
// GIVEN device is in AOD
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
@@ -386,7 +393,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mWakefulnessLifecycle,
mDozeParameters,
mDevicePostureController,
- mDozeLog);
+ mDozeLog,
+ mSystemSettings);
verify(mDevicePostureController).addCallback(postureCallbackCaptor.capture());
// GIVEN device is in AOD
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index e87f1042927f..986d6d541694 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -35,11 +35,11 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -120,11 +120,13 @@ public class DozeSensorsTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
when(mAmbientDisplayConfiguration.tapSensorTypeMapping())
.thenReturn(new String[]{"tapSensor"});
when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
- when(mAmbientDisplayConfiguration.enabled(UserHandle.USER_CURRENT)).thenReturn(true);
+ when(mAmbientDisplayConfiguration.enabled(ActivityManager.getCurrentUser())).thenReturn(
+ true);
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
index 32b994538e12..90644707448a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
@@ -36,6 +36,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.testing.AndroidTestingRunner;
import android.testing.UiThreadTest;
@@ -43,6 +44,7 @@ import android.testing.UiThreadTest;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import org.junit.After;
@@ -73,6 +75,8 @@ public class DozeSuppressorTest extends SysuiTestCase {
private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock
private BiometricUnlockController mBiometricUnlockController;
+ @Mock
+ private UserTracker mUserTracker;
@Mock
private DozeMachine mDozeMachine;
@@ -89,12 +93,14 @@ public class DozeSuppressorTest extends SysuiTestCase {
when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
when(mBiometricUnlockController.hasPendingAuthentication()).thenReturn(false);
when(mDozeHost.isProvisioned()).thenReturn(true);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
mDozeSuppressor = new DozeSuppressor(
mDozeHost,
mConfig,
mDozeLog,
- mBiometricUnlockControllerLazy);
+ mBiometricUnlockControllerLazy,
+ mUserTracker);
mDozeSuppressor.setDozeMachine(mDozeMachine);
}
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 2799a25316d0..ff883eb16bde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -37,9 +37,9 @@ import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import org.junit.Before;
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 4568d1e9b3bd..3b8bb8089910 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -234,6 +234,32 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
}
@Test
+ public void testOnEndDream() throws RemoteException {
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+ // Inform the overlay service of dream starting.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback,
+ LOW_LIGHT_COMPONENT.flattenToString(), false /*shouldShowComplication*/);
+ mMainExecutor.runAllReady();
+
+ // Verify view added.
+ verify(mWindowManager).addView(mViewCaptor.capture(), any());
+
+ // Service destroyed.
+ mService.onEndDream();
+ mMainExecutor.runAllReady();
+
+ // Verify view removed.
+ verify(mWindowManager).removeView(mViewCaptor.getValue());
+
+ // Verify state correctly set.
+ verify(mStateController).setOverlayActive(false);
+ verify(mStateController).setLowLightActive(false);
+ verify(mStateController).setEntryAnimationsFinished(false);
+ }
+
+ @Test
public void testDestroy() throws RemoteException {
final IBinder proxy = mService.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 85c28190d77b..596b903907b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
import android.content.res.Resources;
@@ -47,6 +48,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -109,6 +111,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
View mStatusBarItemView;
@Mock
DreamOverlayStateController mDreamOverlayStateController;
+ @Mock
+ UserTracker mUserTracker;
@Captor
private ArgumentCaptor<DreamOverlayStateController.Callback> mCallbackCaptor;
@@ -125,6 +129,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(NOTIFICATION_INDICATOR_FORMATTER_STRING);
doCallRealMethod().when(mView).setVisibility(anyInt());
doCallRealMethod().when(mView).getVisibility();
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
mController = new DreamOverlayStatusBarViewController(
mView,
@@ -140,7 +145,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
mZenModeController,
mStatusBarWindowStateController,
mDreamOverlayStatusBarItemsProvider,
- mDreamOverlayStateController);
+ mDreamOverlayStateController,
+ mUserTracker);
}
@Test
@@ -282,7 +288,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
mZenModeController,
mStatusBarWindowStateController,
mDreamOverlayStatusBarItemsProvider,
- mDreamOverlayStateController);
+ mDreamOverlayStateController,
+ mUserTracker);
controller.onViewAttached();
verify(mView, never()).showIcon(
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 0a03b2c87f71..c0af0cb4089e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -173,6 +173,7 @@ class CustomizationProviderTest : SysuiTestCase() {
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
set(Flags.REVAMPED_WALLPAPER_UI, true)
+ set(Flags.WALLPAPER_FULLSCREEN_PREVIEW, true)
},
repository = { quickAffordanceRepository },
launchAnimator = launchAnimator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index e9db8cc205fd..b9cfc6550966 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.ActivityManager;
@@ -35,12 +36,12 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.UserHandle;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -71,6 +72,7 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {
private @Mock Context mContext;
private @Mock TaskStackChangeListeners mTaskStackChangeListeners;
private @Mock IActivityTaskManager mIActivityTaskManager;
+ private @Mock UserTracker mUserTracker;
private WorkLockActivityController mController;
private TaskStackChangeListener mTaskStackListener;
@@ -81,12 +83,13 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {
// Set a package name to use for checking ComponentName well-formedness in tests.
doReturn("com.example.test").when(mContext).getPackageName();
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
// Construct controller. Save the TaskStackListener for injecting events.
final ArgumentCaptor<TaskStackChangeListener> listenerCaptor =
ArgumentCaptor.forClass(TaskStackChangeListener.class);
- mController = new WorkLockActivityController(mContext, mTaskStackChangeListeners,
- mIActivityTaskManager);
+ mController = new WorkLockActivityController(mContext, mUserTracker,
+ mTaskStackChangeListeners, mIActivityTaskManager);
verify(mTaskStackChangeListeners).registerTaskStackListener(listenerCaptor.capture());
mTaskStackListener = listenerCaptor.getValue();
@@ -135,7 +138,7 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {
anyInt(),
eq((ProfilerInfo) null),
argThat(hasOptions(taskId, taskOverlay)),
- eq(UserHandle.USER_CURRENT));
+ eq(ActivityManager.getCurrentUser()));
}
private void verifyStartActivity(int taskId, boolean taskOverlay) throws Exception {
@@ -151,7 +154,7 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {
anyInt(),
eq((ProfilerInfo) null),
argThat(hasOptions(taskId, taskOverlay)),
- eq(UserHandle.USER_CURRENT));
+ eq(ActivityManager.getCurrentUser()));
}
private static ArgumentMatcher<Intent> hasComponent(final Context context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index 7205f3068abb..8da4eae2f64a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -22,15 +22,21 @@ import android.content.Context
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.camera.CameraGestureHelper
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
+import org.mockito.Mockito.anyInt
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class CameraQuickAffordanceConfigTest : SysuiTestCase() {
@@ -62,4 +68,24 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() {
.launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE)
assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result)
}
+
+ @Test
+ fun `getPickerScreenState - default when launchable`() = runTest {
+ setLaunchable(true)
+
+ Truth.assertThat(underTest.getPickerScreenState())
+ .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
+ }
+
+ @Test
+ fun `getPickerScreenState - unavailable when not launchable`() = runTest {
+ setLaunchable(false)
+
+ Truth.assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
+
+ private fun setLaunchable(isLaunchable: Boolean) {
+ whenever(cameraGestureHelper.canCameraGestureBeLaunched(anyInt())).thenReturn(isLaunchable)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index ca44fa18f6c4..8f56b9560ec3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -114,20 +114,8 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun `affordance - missing icon - model is none`() = runBlockingTest {
- setUpState(hasWalletIcon = false)
- var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
-
- val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
-
- assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
-
- job.cancel()
- }
-
- @Test
fun `affordance - no selected card - model is none`() = runBlockingTest {
- setUpState(hasWalletIcon = false)
+ setUpState(hasSelectedCard = false)
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
@@ -165,7 +153,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun `getPickerScreenState - unavailable`() = runTest {
setUpState(
- isWalletEnabled = false,
+ isWalletServiceAvailable = false,
)
assertThat(underTest.getPickerScreenState())
@@ -173,9 +161,9 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun `getPickerScreenState - disabled when there is no icon`() = runTest {
+ fun `getPickerScreenState - disabled when the feature is not enabled`() = runTest {
setUpState(
- hasWalletIcon = false,
+ isWalletEnabled = false,
)
assertThat(underTest.getPickerScreenState())
@@ -194,20 +182,16 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
private fun setUpState(
isWalletEnabled: Boolean = true,
+ isWalletServiceAvailable: Boolean = true,
isWalletQuerySuccessful: Boolean = true,
- hasWalletIcon: Boolean = true,
hasSelectedCard: Boolean = true,
) {
whenever(walletController.isWalletEnabled).thenReturn(isWalletEnabled)
val walletClient: QuickAccessWalletClient = mock()
- val icon: Drawable? =
- if (hasWalletIcon) {
- ICON
- } else {
- null
- }
- whenever(walletClient.tileIcon).thenReturn(icon)
+ whenever(walletClient.tileIcon).thenReturn(ICON)
+ whenever(walletClient.isWalletServiceAvailable).thenReturn(isWalletServiceAvailable)
+
whenever(walletController.walletClient).thenReturn(walletClient)
whenever(walletController.queryWalletCards(any())).thenAnswer { invocation ->
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
new file mode 100644
index 000000000000..805dcec0f5b1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.data.quickaffordance
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.ActivityIntentHelper
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.camera.CameraIntentsWrapper
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
+
+ @Mock private lateinit var activityIntentHelper: ActivityIntentHelper
+
+ private lateinit var underTest: VideoCameraQuickAffordanceConfig
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest =
+ VideoCameraQuickAffordanceConfig(
+ context = context,
+ cameraIntents = CameraIntentsWrapper(context),
+ activityIntentHelper = activityIntentHelper,
+ userTracker = FakeUserTracker(),
+ )
+ }
+
+ @Test
+ fun `lockScreenState - visible when launchable`() = runTest {
+ setLaunchable(true)
+
+ val lockScreenState = collectLastValue(underTest.lockScreenState)
+
+ assertThat(lockScreenState())
+ .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java)
+ }
+
+ @Test
+ fun `lockScreenState - hidden when not launchable`() = runTest {
+ setLaunchable(false)
+
+ val lockScreenState = collectLastValue(underTest.lockScreenState)
+
+ assertThat(lockScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+ }
+
+ @Test
+ fun `getPickerScreenState - default when launchable`() = runTest {
+ setLaunchable(true)
+
+ assertThat(underTest.getPickerScreenState())
+ .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
+ }
+
+ @Test
+ fun `getPickerScreenState - unavailable when not launchable`() = runTest {
+ setLaunchable(false)
+
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
+
+ private fun setLaunchable(isLaunchable: Boolean) {
+ whenever(
+ activityIntentHelper.getTargetActivityInfo(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
+ .thenReturn(
+ if (isLaunchable) {
+ mock()
+ } else {
+ null
+ }
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
new file mode 100644
index 000000000000..c4ae2db93569
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.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.keyguard.data.repository
+
+import android.hardware.biometrics.BiometricSourceType
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+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.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+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 DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Captor private lateinit var callbackCaptor: ArgumentCaptor<KeyguardUpdateMonitorCallback>
+
+ private lateinit var testScope: TestScope
+
+ private lateinit var underTest: DeviceEntryFingerprintAuthRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testScope = TestScope()
+
+ underTest = DeviceEntryFingerprintAuthRepositoryImpl(keyguardUpdateMonitor)
+ }
+
+ @After
+ fun tearDown() {
+ verify(keyguardUpdateMonitor).removeCallback(callbackCaptor.value)
+ }
+
+ @Test
+ fun isLockedOut_whenFingerprintLockoutStateChanges_emitsNewValue() =
+ testScope.runTest {
+ val isLockedOutValue = collectLastValue(underTest.isLockedOut)
+ runCurrent()
+
+ verify(keyguardUpdateMonitor).registerCallback(callbackCaptor.capture())
+ val callback = callbackCaptor.value
+ whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(true)
+
+ callback.onLockedOutStateChanged(BiometricSourceType.FACE)
+ assertThat(isLockedOutValue()).isFalse()
+
+ callback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT)
+ assertThat(isLockedOutValue()).isTrue()
+
+ whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
+ callback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT)
+ assertThat(isLockedOutValue()).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
new file mode 100644
index 000000000000..4b069051423c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.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.keyguard.data.repository
+
+import android.app.trust.TrustManager
+import android.content.pm.UserInfo
+import androidx.test.filters.SmallTest
+import com.android.keyguard.logging.TrustRepositoryLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.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.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class TrustRepositoryTest : SysuiTestCase() {
+ @Mock private lateinit var trustManager: TrustManager
+ @Captor private lateinit var listenerCaptor: ArgumentCaptor<TrustManager.TrustListener>
+ private lateinit var userRepository: FakeUserRepository
+ private lateinit var testScope: TestScope
+ private val users = listOf(UserInfo(1, "user 1", 0), UserInfo(2, "user 1", 0))
+
+ private lateinit var underTest: TrustRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testScope = TestScope()
+ userRepository = FakeUserRepository()
+ userRepository.setUserInfos(users)
+
+ val logger =
+ TrustRepositoryLogger(
+ LogBuffer("TestBuffer", 1, mock(LogcatEchoTracker::class.java), false)
+ )
+ underTest =
+ TrustRepositoryImpl(testScope.backgroundScope, userRepository, trustManager, logger)
+ }
+
+ @Test
+ fun isCurrentUserTrusted_whenTrustChanges_emitsLatestValue() =
+ testScope.runTest {
+ runCurrent()
+ verify(trustManager).registerTrustListener(listenerCaptor.capture())
+ val listener = listenerCaptor.value
+
+ val currentUserId = users[0].id
+ userRepository.setSelectedUserInfo(users[0])
+ val isCurrentUserTrusted = collectLastValue(underTest.isCurrentUserTrusted)
+
+ listener.onTrustChanged(true, false, currentUserId, 0, emptyList())
+ assertThat(isCurrentUserTrusted()).isTrue()
+
+ listener.onTrustChanged(false, false, currentUserId, 0, emptyList())
+
+ assertThat(isCurrentUserTrusted()).isFalse()
+ }
+
+ @Test
+ fun isCurrentUserTrusted_isFalse_byDefault() =
+ testScope.runTest {
+ runCurrent()
+
+ val isCurrentUserTrusted = collectLastValue(underTest.isCurrentUserTrusted)
+
+ assertThat(isCurrentUserTrusted()).isFalse()
+ }
+
+ @Test
+ fun isCurrentUserTrusted_whenTrustChangesForDifferentUser_noop() =
+ testScope.runTest {
+ runCurrent()
+ verify(trustManager).registerTrustListener(listenerCaptor.capture())
+ userRepository.setSelectedUserInfo(users[0])
+ val listener = listenerCaptor.value
+
+ val isCurrentUserTrusted = collectLastValue(underTest.isCurrentUserTrusted)
+ // current user is trusted.
+ listener.onTrustChanged(true, true, users[0].id, 0, emptyList())
+ // some other user is not trusted.
+ listener.onTrustChanged(false, false, users[1].id, 0, emptyList())
+
+ assertThat(isCurrentUserTrusted()).isTrue()
+ }
+
+ @Test
+ fun isCurrentUserTrusted_whenTrustChangesForCurrentUser_emitsNewValue() =
+ testScope.runTest {
+ runCurrent()
+ verify(trustManager).registerTrustListener(listenerCaptor.capture())
+ val listener = listenerCaptor.value
+ userRepository.setSelectedUserInfo(users[0])
+
+ val isCurrentUserTrusted = collectLastValue(underTest.isCurrentUserTrusted)
+ listener.onTrustChanged(true, true, users[0].id, 0, emptyList())
+ assertThat(isCurrentUserTrusted()).isTrue()
+
+ listener.onTrustChanged(false, true, users[0].id, 0, emptyList())
+ assertThat(isCurrentUserTrusted()).isFalse()
+ }
+
+ @Test
+ fun isCurrentUserTrusted_whenUserChangesWithoutRecentTrustChange_defaultsToFalse() =
+ testScope.runTest {
+ runCurrent()
+ verify(trustManager).registerTrustListener(listenerCaptor.capture())
+ val listener = listenerCaptor.value
+ userRepository.setSelectedUserInfo(users[0])
+ listener.onTrustChanged(true, true, users[0].id, 0, emptyList())
+
+ val isCurrentUserTrusted = collectLastValue(underTest.isCurrentUserTrusted)
+ userRepository.setSelectedUserInfo(users[1])
+
+ assertThat(isCurrentUserTrusted()).isFalse()
+ }
+
+ @Test
+ fun isCurrentUserTrusted_trustChangesFirstBeforeUserInfoChanges_emitsCorrectValue() =
+ testScope.runTest {
+ runCurrent()
+ verify(trustManager).registerTrustListener(listenerCaptor.capture())
+ val listener = listenerCaptor.value
+ val isCurrentUserTrusted = collectLastValue(underTest.isCurrentUserTrusted)
+
+ listener.onTrustChanged(true, true, users[0].id, 0, emptyList())
+ assertThat(isCurrentUserTrusted()).isFalse()
+
+ userRepository.setSelectedUserInfo(users[0])
+
+ assertThat(isCurrentUserTrusted()).isTrue()
+ }
+}
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 a1b6d478d799..5a7a3d49b628 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
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
@@ -56,6 +57,7 @@ import org.mockito.MockitoAnnotations
*/
@SmallTest
@RunWith(JUnit4::class)
+@FlakyTest(bugId = 265303901)
class KeyguardTransitionScenariosTest : SysuiTestCase() {
private lateinit var testScope: TestScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
index db9c4e713e37..fbfeca9c2a25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor
import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.phone.KeyguardBouncer
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,8 +33,10 @@ class PrimaryBouncerCallbackInteractorTest : SysuiTestCase() {
private val mPrimaryBouncerCallbackInteractor = PrimaryBouncerCallbackInteractor()
@Mock
private lateinit var mPrimaryBouncerExpansionCallback:
- KeyguardBouncer.PrimaryBouncerExpansionCallback
- @Mock private lateinit var keyguardResetCallback: KeyguardBouncer.KeyguardResetCallback
+ PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
+ @Mock
+ private lateinit var keyguardResetCallback:
+ PrimaryBouncerCallbackInteractor.KeyguardResetCallback
@Before
fun setup() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 094d69a9d392..9a0bd9e4b0df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -243,6 +243,13 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
}
@Test
+ public void dismissDialog_closesDialogByBroadcastSender() {
+ mMediaOutputBaseDialogImpl.dismissDialog();
+
+ verify(mBroadcastSender).closeSystemDialogs();
+ }
+
+ @Test
public void whenBroadcasting_verifyLeBroadcastServiceCallBackIsRegisteredAndUnregistered() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index f5432e22c57e..117751c47004 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -252,6 +252,13 @@ public class MediaOutputControllerTest extends SysuiTestCase {
}
@Test
+ public void tryToLaunchMediaApplication_nullIntent_skip() {
+ mMediaOutputController.tryToLaunchMediaApplication();
+
+ verify(mCb, never()).dismissDialog();
+ }
+
+ @Test
public void onDevicesUpdated_unregistersNearbyDevicesCallback() throws RemoteException {
mMediaOutputController.start(mCb);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt
index 9c4e849df738..b3e621e32d08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt
@@ -48,6 +48,7 @@ class FakeMediaTttChipControllerReceiver(
viewUtil: ViewUtil,
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
+ rippleController: MediaTttReceiverRippleController,
) :
MediaTttChipControllerReceiver(
commandQueue,
@@ -65,6 +66,7 @@ class FakeMediaTttChipControllerReceiver(
viewUtil,
wakeLockBuilder,
systemClock,
+ rippleController,
) {
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
// Just bypass the animation in tests
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index cefc7424324b..5e40898030cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -85,6 +85,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
private lateinit var windowManager: WindowManager
@Mock
private lateinit var commandQueue: CommandQueue
+ @Mock
+ private lateinit var rippleController: MediaTttReceiverRippleController
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
private lateinit var uiEventLoggerFake: UiEventLoggerFake
@@ -134,6 +136,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
viewUtil,
fakeWakeLockBuilder,
fakeClock,
+ rippleController,
)
controllerReceiver.start()
@@ -163,6 +166,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
viewUtil,
fakeWakeLockBuilder,
fakeClock,
+ rippleController,
)
controllerReceiver.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
index f5b3959b322d..54d4460af6e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
@@ -45,13 +45,18 @@ import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo
import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger
import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator
+import com.android.systemui.temporarydisplay.chipbar.SwipeChipbarAwayGestureHandler
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.view.ViewUtil
import com.android.systemui.util.wakelock.WakeLockFake
@@ -61,6 +66,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
+import org.mockito.Mockito.atLeast
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -93,6 +99,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Mock private lateinit var viewUtil: ViewUtil
@Mock private lateinit var windowManager: WindowManager
@Mock private lateinit var vibratorHelper: VibratorHelper
+ @Mock private lateinit var swipeHandler: SwipeChipbarAwayGestureHandler
private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder
private lateinit var fakeWakeLock: WakeLockFake
private lateinit var chipbarCoordinator: ChipbarCoordinator
@@ -143,6 +150,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
powerManager,
falsingManager,
falsingCollector,
+ swipeHandler,
viewUtil,
vibratorHelper,
fakeWakeLockBuilder,
@@ -161,9 +169,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
)
underTest.start()
- val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
- verify(commandQueue).addCallback(callbackCaptor.capture())
- commandQueueCallback = callbackCaptor.value!!
+ setCommandQueueCallback()
}
@Test
@@ -920,6 +926,172 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
verify(windowManager).removeView(any())
}
+ @Test
+ fun newState_viewListenerRegistered() {
+ val mockChipbarCoordinator = mock<ChipbarCoordinator>()
+ underTest =
+ MediaTttSenderCoordinator(
+ mockChipbarCoordinator,
+ commandQueue,
+ context,
+ logger,
+ mediaTttFlags,
+ uiEventLogger,
+ )
+ underTest.start()
+ // Re-set the command queue callback since we've created a new [MediaTttSenderCoordinator]
+ // with a new callback.
+ setCommandQueueCallback()
+
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ routeInfo,
+ null,
+ )
+
+ verify(mockChipbarCoordinator).registerListener(any())
+ }
+
+ @Test
+ fun onInfoPermanentlyRemoved_viewListenerUnregistered() {
+ val mockChipbarCoordinator = mock<ChipbarCoordinator>()
+ underTest =
+ MediaTttSenderCoordinator(
+ mockChipbarCoordinator,
+ commandQueue,
+ context,
+ logger,
+ mediaTttFlags,
+ uiEventLogger,
+ )
+ underTest.start()
+ setCommandQueueCallback()
+
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ routeInfo,
+ null,
+ )
+
+ val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>()
+ verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor))
+
+ // WHEN the listener is notified that the view has been removed
+ listenerCaptor.value.onInfoPermanentlyRemoved(DEFAULT_ID)
+
+ // THEN the media coordinator unregisters the listener
+ verify(mockChipbarCoordinator).unregisterListener(listenerCaptor.value)
+ }
+
+ @Test
+ fun onInfoPermanentlyRemoved_wrongId_viewListenerNotUnregistered() {
+ val mockChipbarCoordinator = mock<ChipbarCoordinator>()
+ underTest =
+ MediaTttSenderCoordinator(
+ mockChipbarCoordinator,
+ commandQueue,
+ context,
+ logger,
+ mediaTttFlags,
+ uiEventLogger,
+ )
+ underTest.start()
+ setCommandQueueCallback()
+
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ routeInfo,
+ null,
+ )
+
+ val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>()
+ verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor))
+
+ // WHEN the listener is notified that a different view has been removed
+ listenerCaptor.value.onInfoPermanentlyRemoved("differentViewId")
+
+ // THEN the media coordinator doesn't unregister the listener
+ verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value)
+ }
+
+ @Test
+ fun farFromReceiverState_viewListenerUnregistered() {
+ val mockChipbarCoordinator = mock<ChipbarCoordinator>()
+ underTest =
+ MediaTttSenderCoordinator(
+ mockChipbarCoordinator,
+ commandQueue,
+ context,
+ logger,
+ mediaTttFlags,
+ uiEventLogger,
+ )
+ underTest.start()
+ setCommandQueueCallback()
+
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ routeInfo,
+ null,
+ )
+
+ val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>()
+ verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor))
+
+ // WHEN we go to the FAR_FROM_RECEIVER state
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+ routeInfo,
+ null
+ )
+
+ // THEN the media coordinator unregisters the listener
+ verify(mockChipbarCoordinator).unregisterListener(listenerCaptor.value)
+ }
+
+ @Test
+ fun statesWithDifferentIds_onInfoPermanentlyRemovedForOneId_viewListenerNotUnregistered() {
+ val mockChipbarCoordinator = mock<ChipbarCoordinator>()
+ underTest =
+ MediaTttSenderCoordinator(
+ mockChipbarCoordinator,
+ commandQueue,
+ context,
+ logger,
+ mediaTttFlags,
+ uiEventLogger,
+ )
+ underTest.start()
+ setCommandQueueCallback()
+
+ // WHEN there are two different media transfers with different IDs
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ MediaRoute2Info.Builder("route1", OTHER_DEVICE_NAME)
+ .addFeature("feature")
+ .setClientPackageName(PACKAGE_NAME)
+ .build(),
+ null,
+ )
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ MediaRoute2Info.Builder("route2", OTHER_DEVICE_NAME)
+ .addFeature("feature")
+ .setClientPackageName(PACKAGE_NAME)
+ .build(),
+ null,
+ )
+
+ val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>()
+ verify(mockChipbarCoordinator, atLeast(1)).registerListener(capture(listenerCaptor))
+
+ // THEN one of them is removed
+ listenerCaptor.value.onInfoPermanentlyRemoved("route1")
+
+ // THEN the media coordinator doesn't unregister the listener (since route2 is still active)
+ verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value)
+ }
+
private fun getChipbarView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
@@ -960,8 +1132,16 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
null
)
}
+
+ private fun setCommandQueueCallback() {
+ val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>()
+ verify(commandQueue).addCallback(capture(callbackCaptor))
+ commandQueueCallback = callbackCaptor.value
+ reset(commandQueue)
+ }
}
+private const val DEFAULT_ID = "defaultId"
private const val APP_NAME = "Fake app name"
private const val OTHER_DEVICE_NAME = "My Tablet"
private const val BLANK_DEVICE_NAME = " "
@@ -969,13 +1149,13 @@ private const val PACKAGE_NAME = "com.android.systemui"
private const val TIMEOUT = 10000
private val routeInfo =
- MediaRoute2Info.Builder("id", OTHER_DEVICE_NAME)
+ MediaRoute2Info.Builder(DEFAULT_ID, OTHER_DEVICE_NAME)
.addFeature("feature")
.setClientPackageName(PACKAGE_NAME)
.build()
private val routeInfoWithBlankDeviceName =
- MediaRoute2Info.Builder("id", BLANK_DEVICE_NAME)
+ MediaRoute2Info.Builder(DEFAULT_ID, BLANK_DEVICE_NAME)
.addFeature("feature")
.setClientPackageName(PACKAGE_NAME)
.build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index 1bc4719c70b7..1a35502ceed6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -31,10 +31,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -69,7 +66,7 @@ public class ColorSchemeTest extends SysuiTestCase {
// Expressive applies hue rotations to the theme color. The input theme color has hue
// 117, ensuring the hue changed significantly is a strong signal styles are being applied.
ColorScheme colorScheme = new ColorScheme(wallpaperColors, false, Style.EXPRESSIVE);
- Assert.assertEquals(357.77, Cam.fromInt(colorScheme.getAccent1().get(6)).getHue(), 0.1);
+ Assert.assertEquals(357.77, Cam.fromInt(colorScheme.getAccent1().getS500()).getHue(), 0.1);
}
@@ -111,7 +108,8 @@ public class ColorSchemeTest extends SysuiTestCase {
public void testTertiaryHueWrapsProperly() {
int colorInt = 0xffB3588A; // H350 C50 T50
ColorScheme colorScheme = new ColorScheme(colorInt, false /* darkTheme */);
- int tertiaryMid = colorScheme.getAccent3().get(colorScheme.getAccent3().size() / 2);
+ int tertiaryMid = colorScheme.getAccent3().getAllShades().get(
+ colorScheme.getShadeCount() / 2);
Cam cam = Cam.fromInt(tertiaryMid);
Assert.assertEquals(cam.getHue(), 50.0, 10.0);
}
@@ -121,7 +119,8 @@ public class ColorSchemeTest extends SysuiTestCase {
int colorInt = 0xffB3588A; // H350 C50 T50
ColorScheme colorScheme = new ColorScheme(colorInt, false /* darkTheme */,
Style.SPRITZ /* style */);
- int primaryMid = colorScheme.getAccent1().get(colorScheme.getAccent1().size() / 2);
+ int primaryMid = colorScheme.getAccent1().getAllShades().get(
+ colorScheme.getShadeCount() / 2);
Cam cam = Cam.fromInt(primaryMid);
Assert.assertEquals(cam.getChroma(), 12.0, 1.0);
}
@@ -131,7 +130,8 @@ public class ColorSchemeTest extends SysuiTestCase {
int colorInt = 0xffB3588A; // H350 C50 T50
ColorScheme colorScheme = new ColorScheme(colorInt, false /* darkTheme */,
Style.VIBRANT /* style */);
- int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
+ int neutralMid = colorScheme.getNeutral1().getAllShades().get(
+ colorScheme.getShadeCount() / 2);
Cam cam = Cam.fromInt(neutralMid);
Assert.assertTrue("chroma was " + cam.getChroma(), Math.floor(cam.getChroma()) <= 12.0);
}
@@ -141,7 +141,8 @@ public class ColorSchemeTest extends SysuiTestCase {
int colorInt = 0xffB3588A; // H350 C50 T50
ColorScheme colorScheme = new ColorScheme(colorInt, false /* darkTheme */,
Style.EXPRESSIVE /* style */);
- int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
+ int neutralMid = colorScheme.getNeutral1().getAllShades().get(
+ colorScheme.getShadeCount() / 2);
Cam cam = Cam.fromInt(neutralMid);
Assert.assertTrue(cam.getChroma() <= 8.0);
}
@@ -151,10 +152,11 @@ public class ColorSchemeTest extends SysuiTestCase {
int colorInt = 0xffB3588A; // H350 C50 T50
ColorScheme colorScheme = new ColorScheme(colorInt, false /* darkTheme */,
Style.MONOCHROMATIC /* style */);
- int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
+ int neutralMid = colorScheme.getNeutral1().getAllShades().get(
+ colorScheme.getShadeCount() / 2);
Assert.assertTrue(
Color.red(neutralMid) == Color.green(neutralMid)
- && Color.green(neutralMid) == Color.blue(neutralMid)
+ && Color.green(neutralMid) == Color.blue(neutralMid)
);
}
@@ -190,15 +192,14 @@ public class ColorSchemeTest extends SysuiTestCase {
xml.append(" <").append(styleName).append(">");
List<String> colors = new ArrayList<>();
- for (Stream<Integer> stream: Arrays.asList(colorScheme.getAccent1().stream(),
- colorScheme.getAccent2().stream(),
- colorScheme.getAccent3().stream(),
- colorScheme.getNeutral1().stream(),
- colorScheme.getNeutral2().stream())) {
+
+ colorScheme.getAllHues().forEach(schemeHue -> {
colors.add("ffffff");
- colors.addAll(stream.map(Integer::toHexString).map(s -> s.substring(2)).collect(
- Collectors.toList()));
- }
+ schemeHue.getAllShades().forEach(tone -> {
+ colors.add(Integer.toHexString(tone).substring(2));
+ });
+ });
+
xml.append(String.join(",", colors));
xml.append("</").append(styleName).append(">\n");
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 8b0342eda633..8058b85e205a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -55,8 +55,8 @@ import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.pip.Pip;
@@ -109,7 +109,8 @@ public class NavigationBarControllerTest extends SysuiTestCase {
TaskStackChangeListeners.getTestInstance(),
Optional.of(mock(Pip.class)),
Optional.of(mock(BackAnimation.class)),
- mock(FeatureFlags.class)));
+ mock(FeatureFlags.class),
+ mock(SecureSettings.class)));
initializeNavigationBars();
mMockitoSession = mockitoSession().mockStatic(Utilities.class).startMocking();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
new file mode 100644
index 000000000000..a1d42a0ce505
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.notetask.quickaffordance
+
+import android.test.suitebuilder.annotation.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
+import com.android.systemui.notetask.NoteTaskController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+/**
+ * Tests for [NoteTaskQuickAffordanceConfig].
+ *
+ * Build/Install/Run:
+ * - atest SystemUITests:NoteTaskQuickAffordanceConfigTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
+
+ @Mock lateinit var noteTaskController: NoteTaskController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(noteTaskController.showNoteTask()).then {}
+ }
+
+ private fun createUnderTest(isEnabled: Boolean) =
+ NoteTaskQuickAffordanceConfig(
+ context = context,
+ noteTaskController = noteTaskController,
+ isEnabled = isEnabled,
+ )
+
+ @Test
+ fun lockScreenState_isNotEnabled_shouldEmitHidden() = runTest {
+ val underTest = createUnderTest(isEnabled = false)
+
+ val actual = collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual()).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Test
+ fun lockScreenState_isEnabled_shouldEmitVisible() = runTest {
+ val stringResult = "Notetaking"
+ val underTest = createUnderTest(isEnabled = true)
+
+ val actual = collectLastValue(underTest.lockScreenState)
+
+ val expected =
+ LockScreenState.Visible(
+ icon =
+ Icon.Resource(
+ res = R.drawable.ic_note_task_shortcut_keyguard,
+ contentDescription = ContentDescription.Loaded(stringResult),
+ )
+ )
+ assertThat(actual()).isEqualTo(expected)
+ }
+
+ @Test
+ fun onTriggered_shouldLaunchNoteTask() {
+ val underTest = createUnderTest(isEnabled = false)
+
+ underTest.onTriggered(expandable = null)
+
+ verify(noteTaskController).showNoteTask()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index a56990f40b90..4a6158f57f6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
@@ -53,6 +54,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.NotificationChannels;
@@ -82,6 +84,8 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
@Mock
private UiEventLogger mUiEventLogger;
@Mock
+ private UserTracker mUserTracker;
+ @Mock
private View mView;
private BroadcastReceiver mReceiver;
@@ -103,8 +107,12 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
ActivityStarter starter = mDependency.injectMockDependency(ActivityStarter.class);
BroadcastSender broadcastSender = mDependency.injectMockDependency(BroadcastSender.class);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
+ when(mUserTracker.getUserHandle()).thenReturn(
+ UserHandle.of(ActivityManager.getCurrentUser()));
mPowerNotificationWarnings = new PowerNotificationWarnings(wrapper, starter,
- broadcastSender, () -> mBatteryController, mDialogLaunchAnimator, mUiEventLogger);
+ broadcastSender, () -> mBatteryController, mDialogLaunchAnimator, mUiEventLogger,
+ mUserTracker);
BatteryStateSnapshot snapshot = new BatteryStateSnapshot(100, false, false, 1,
BatteryManager.BATTERY_HEALTH_GOOD, 5, 15);
mPowerNotificationWarnings.updateSnapshot(snapshot);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
index 46a502acba16..ed3f1a059e61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -22,15 +22,12 @@ import android.graphics.ColorSpace
import android.graphics.Insets
import android.graphics.Rect
import android.hardware.HardwareBuffer
-import android.os.Bundle
import android.os.UserHandle
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
-import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap
-import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
+import com.android.internal.util.ScreenshotRequest
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
@@ -49,7 +46,6 @@ class RequestProcessorTest {
private val bounds = Rect(25, 25, 75, 75)
private val scope = CoroutineScope(Dispatchers.Unconfined)
- private val dispatcher = Dispatchers.Unconfined
private val policy = FakeScreenshotPolicy()
private val flags = FakeFeatureFlags()
@@ -58,7 +54,8 @@ class RequestProcessorTest {
fun testProcessAsync() {
flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
- val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD).build()
val processor = RequestProcessor(imageCapture, policy, flags, scope)
var result: ScreenshotRequest? = null
@@ -80,7 +77,8 @@ class RequestProcessorTest {
fun testFullScreenshot_workProfilePolicyDisabled() = runBlocking {
flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
- val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD).build()
val processor = RequestProcessor(imageCapture, policy, flags, scope)
val processedRequest = processor.process(request)
@@ -97,9 +95,11 @@ class RequestProcessorTest {
policy.setManagedProfile(USER_ID, false)
policy.setDisplayContentInfo(
policy.getDefaultDisplayId(),
- DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
+ DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)
+ )
- val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER).build()
val processor = RequestProcessor(imageCapture, policy, flags, scope)
val processedRequest = processor.process(request)
@@ -120,17 +120,20 @@ class RequestProcessorTest {
// Indicate that the primary content belongs to a manged profile
policy.setManagedProfile(USER_ID, true)
- policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
- DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
+ policy.setDisplayContentInfo(
+ policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)
+ )
- val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD).build()
val processor = RequestProcessor(imageCapture, policy, flags, scope)
val processedRequest = processor.process(request)
// Expect a task snapshot is taken, overriding the full screen mode
assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
- assertThat(bitmap.equalsHardwareBitmapBundle(processedRequest.bitmapBundle)).isTrue()
+ assertThat(bitmap.equalsHardwareBitmap(processedRequest.bitmap)).isTrue()
assertThat(processedRequest.boundsInScreen).isEqualTo(bounds)
assertThat(processedRequest.insets).isEqualTo(Insets.NONE)
assertThat(processedRequest.taskId).isEqualTo(TASK_ID)
@@ -147,10 +150,16 @@ class RequestProcessorTest {
val processor = RequestProcessor(imageCapture, policy, flags, scope)
val bitmap = makeHardwareBitmap(100, 100)
- val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
- val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
- bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER)
+ .setTopComponent(component)
+ .setTaskId(TASK_ID)
+ .setUserId(USER_ID)
+ .setBitmap(bitmap)
+ .setBoundsOnScreen(bounds)
+ .setInsets(Insets.NONE)
+ .build()
val processedRequest = processor.process(request)
@@ -168,10 +177,16 @@ class RequestProcessorTest {
policy.setManagedProfile(USER_ID, false)
val bitmap = makeHardwareBitmap(100, 100)
- val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
- val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
- bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER)
+ .setTopComponent(component)
+ .setTaskId(TASK_ID)
+ .setUserId(USER_ID)
+ .setBitmap(bitmap)
+ .setBoundsOnScreen(bounds)
+ .setInsets(Insets.NONE)
+ .build()
val processedRequest = processor.process(request)
@@ -190,10 +205,16 @@ class RequestProcessorTest {
policy.setManagedProfile(USER_ID, true)
val bitmap = makeHardwareBitmap(100, 100)
- val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
- val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
- bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER)
+ .setTopComponent(component)
+ .setTaskId(TASK_ID)
+ .setUserId(USER_ID)
+ .setBitmap(bitmap)
+ .setBoundsOnScreen(bounds)
+ .setInsets(Insets.NONE)
+ .build()
val processedRequest = processor.process(request)
@@ -202,14 +223,18 @@ class RequestProcessorTest {
}
private fun makeHardwareBitmap(width: Int, height: Int): Bitmap {
- val buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, 1,
- HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
+ val buffer =
+ HardwareBuffer.create(
+ width,
+ height,
+ HardwareBuffer.RGBA_8888,
+ 1,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+ )
return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
}
- private fun Bitmap.equalsHardwareBitmapBundle(bundle: Bundle): Boolean {
- val provided = bundleToHardwareBitmap(bundle)
- return provided.hardwareBuffer == this.hardwareBuffer &&
- provided.colorSpace == this.colorSpace
+ private fun Bitmap.equalsHardwareBitmap(bitmap: Bitmap): Boolean {
+ return bitmap.hardwareBuffer == this.hardwareBuffer && bitmap.colorSpace == this.colorSpace
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index 99c79b0365ae..f93501928844 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -35,8 +35,7 @@ import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
-import com.android.internal.util.ScreenshotHelper
-import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
+import com.android.internal.util.ScreenshotRequest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
@@ -80,24 +79,39 @@ class TakeScreenshotServiceTest : SysuiTestCase() {
private val flags = FakeFeatureFlags()
private val topComponent = ComponentName(mContext, TakeScreenshotServiceTest::class.java)
- private val service = TakeScreenshotService(
- controller, userManager, devicePolicyManager, eventLogger,
- notificationsController, mContext, Runnable::run, flags, requestProcessor)
+ private val service =
+ TakeScreenshotService(
+ controller,
+ userManager,
+ devicePolicyManager,
+ eventLogger,
+ notificationsController,
+ mContext,
+ Runnable::run,
+ flags,
+ requestProcessor
+ )
@Before
fun setUp() {
whenever(devicePolicyManager.resources).thenReturn(devicePolicyResourcesManager)
- whenever(devicePolicyManager.getScreenCaptureDisabled(
- /* admin component (null: any admin) */ isNull(), eq(UserHandle.USER_ALL)))
+ whenever(
+ devicePolicyManager.getScreenCaptureDisabled(
+ /* admin component (null: any admin) */ isNull(),
+ eq(UserHandle.USER_ALL)
+ )
+ )
.thenReturn(false)
whenever(userManager.isUserUnlocked).thenReturn(true)
// Stub request processor as a synchronous no-op for tests with the flag enabled
doAnswer {
- val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest
- val consumer: Consumer<ScreenshotRequest> = it.getArgument(1)
- consumer.accept(request)
- }.`when`(requestProcessor).processAsync(/* request= */ any(), /* callback= */ any())
+ val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest
+ val consumer: Consumer<ScreenshotRequest> = it.getArgument(1)
+ consumer.accept(request)
+ }
+ .`when`(requestProcessor)
+ .processAsync(/* request= */ any(), /* callback= */ any())
// Flipped in selected test cases
flags.set(SCREENSHOT_WORK_PROFILE_POLICY, false)
@@ -108,7 +122,8 @@ class TakeScreenshotServiceTest : SysuiTestCase() {
/* className = */ null,
/* token = */ null,
application,
- /* activityManager = */ null)
+ /* activityManager = */ null
+ )
}
@Test
@@ -125,63 +140,89 @@ class TakeScreenshotServiceTest : SysuiTestCase() {
@Test
fun takeScreenshotFullscreen() {
- val request = ScreenshotRequest(
- TAKE_SCREENSHOT_FULLSCREEN,
- SCREENSHOT_KEY_CHORD,
- topComponent)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ .setTopComponent(topComponent)
+ .build()
- service.handleRequest(request, { /* onSaved */ }, callback)
+ service.handleRequest(request, { /* onSaved */}, callback)
- verify(controller, times(1)).takeScreenshotFullscreen(
- eq(topComponent),
- /* onSavedListener = */ any(),
- /* requestCallback = */ any())
+ verify(controller, times(1))
+ .takeScreenshotFullscreen(
+ eq(topComponent),
+ /* onSavedListener = */ any(),
+ /* requestCallback = */ any()
+ )
assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1)
val logEvent = eventLogger.get(0)
- assertEquals("Expected SCREENSHOT_REQUESTED UiEvent",
- logEvent.eventId, SCREENSHOT_REQUESTED_KEY_CHORD.id)
- assertEquals("Expected supplied package name",
- topComponent.packageName, eventLogger.get(0).packageName)
+ assertEquals(
+ "Expected SCREENSHOT_REQUESTED UiEvent",
+ logEvent.eventId,
+ SCREENSHOT_REQUESTED_KEY_CHORD.id
+ )
+ assertEquals(
+ "Expected supplied package name",
+ topComponent.packageName,
+ eventLogger.get(0).packageName
+ )
}
@Test
fun takeScreenshotProvidedImage() {
val bounds = Rect(50, 50, 150, 150)
val bitmap = makeHardwareBitmap(100, 100)
- val bitmapBundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
-
- val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW,
- bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, topComponent)
-
- service.handleRequest(request, { /* onSaved */ }, callback)
- verify(controller, times(1)).handleImageAsScreenshot(
- argThat { b -> b.equalsHardwareBitmap(bitmap) },
- eq(bounds),
- eq(Insets.NONE), eq(TASK_ID), eq(USER_ID), eq(topComponent),
- /* onSavedListener = */ any(), /* requestCallback = */ any())
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW)
+ .setTopComponent(topComponent)
+ .setTaskId(TASK_ID)
+ .setUserId(USER_ID)
+ .setBitmap(bitmap)
+ .setBoundsOnScreen(bounds)
+ .setInsets(Insets.NONE)
+ .build()
+
+ service.handleRequest(request, { /* onSaved */}, callback)
+
+ verify(controller, times(1))
+ .handleImageAsScreenshot(
+ argThat { b -> b.equalsHardwareBitmap(bitmap) },
+ eq(bounds),
+ eq(Insets.NONE),
+ eq(TASK_ID),
+ eq(USER_ID),
+ eq(topComponent),
+ /* onSavedListener = */ any(),
+ /* requestCallback = */ any()
+ )
assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1)
val logEvent = eventLogger.get(0)
- assertEquals("Expected SCREENSHOT_REQUESTED_* UiEvent",
- logEvent.eventId, SCREENSHOT_REQUESTED_OVERVIEW.id)
- assertEquals("Expected supplied package name",
- topComponent.packageName, eventLogger.get(0).packageName)
+ assertEquals(
+ "Expected SCREENSHOT_REQUESTED_* UiEvent",
+ logEvent.eventId,
+ SCREENSHOT_REQUESTED_OVERVIEW.id
+ )
+ assertEquals(
+ "Expected supplied package name",
+ topComponent.packageName,
+ eventLogger.get(0).packageName
+ )
}
@Test
fun takeScreenshotFullscreen_userLocked() {
whenever(userManager.isUserUnlocked).thenReturn(false)
- val request = ScreenshotRequest(
- TAKE_SCREENSHOT_FULLSCREEN,
- SCREENSHOT_KEY_CHORD,
- topComponent)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ .setTopComponent(topComponent)
+ .build()
- service.handleRequest(request, { /* onSaved */ }, callback)
+ service.handleRequest(request, { /* onSaved */}, callback)
verify(notificationsController, times(1)).notifyScreenshotError(anyInt())
verify(callback, times(1)).reportError()
@@ -190,21 +231,24 @@ class TakeScreenshotServiceTest : SysuiTestCase() {
@Test
fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers() {
- whenever(devicePolicyManager.getScreenCaptureDisabled(
- isNull(), eq(UserHandle.USER_ALL))
- ).thenReturn(true)
+ whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL)))
+ .thenReturn(true)
- whenever(devicePolicyResourcesManager.getString(
- eq(SCREENSHOT_BLOCKED_BY_ADMIN),
- /* Supplier<String> */ any(),
- )).thenReturn("SCREENSHOT_BLOCKED_BY_ADMIN")
+ whenever(
+ devicePolicyResourcesManager.getString(
+ eq(SCREENSHOT_BLOCKED_BY_ADMIN),
+ /* Supplier<String> */
+ any(),
+ )
+ )
+ .thenReturn("SCREENSHOT_BLOCKED_BY_ADMIN")
- val request = ScreenshotRequest(
- TAKE_SCREENSHOT_FULLSCREEN,
- SCREENSHOT_KEY_CHORD,
- topComponent)
+ val request =
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ .setTopComponent(topComponent)
+ .build()
- service.handleRequest(request, { /* onSaved */ }, callback)
+ service.handleRequest(request, { /* onSaved */}, callback)
// error shown: Toast.makeText(...).show(), untestable
verify(callback, times(1)).reportError()
@@ -214,14 +258,20 @@ class TakeScreenshotServiceTest : SysuiTestCase() {
private fun Bitmap.equalsHardwareBitmap(other: Bitmap): Boolean {
return config == HARDWARE &&
- other.config == HARDWARE &&
- hardwareBuffer == other.hardwareBuffer &&
- colorSpace == other.colorSpace
+ other.config == HARDWARE &&
+ hardwareBuffer == other.hardwareBuffer &&
+ colorSpace == other.colorSpace
}
/** A hardware Bitmap is mandated by use of ScreenshotHelper.HardwareBitmapBundler */
private fun makeHardwareBitmap(width: Int, height: Int): Bitmap {
- val buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, 1,
- HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
+ val buffer =
+ HardwareBuffer.create(
+ width,
+ height,
+ HardwareBuffer.RGBA_8888,
+ 1,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+ )
return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
index f802a5e09228..ed9baf5b1c9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
@@ -109,11 +109,12 @@ class CombinedShadeHeaderConstraintsTest : SysuiTestCase() {
@Test
fun testEdgeElementsAlignedWithEdge_largeScreen() {
with(largeScreenConstraint) {
- assertThat(getConstraint(R.id.clock).layout.startToStart).isEqualTo(PARENT_ID)
- assertThat(getConstraint(R.id.clock).layout.horizontalBias).isEqualTo(0f)
+ assertThat(getConstraint(R.id.clock).layout.startToEnd).isEqualTo(R.id.begin_guide)
+ assertThat(getConstraint(R.id.clock).layout.horizontalBias).isEqualTo(0.5f)
- assertThat(getConstraint(R.id.privacy_container).layout.endToEnd).isEqualTo(PARENT_ID)
- assertThat(getConstraint(R.id.privacy_container).layout.horizontalBias).isEqualTo(1f)
+ assertThat(getConstraint(R.id.privacy_container).layout.endToStart)
+ .isEqualTo(R.id.end_guide)
+ assertThat(getConstraint(R.id.privacy_container).layout.horizontalBias).isEqualTo(0.5f)
}
}
@@ -219,7 +220,12 @@ class CombinedShadeHeaderConstraintsTest : SysuiTestCase() {
.isEqualTo(cutoutEnd - padding)
}
- assertThat(changes.largeScreenConstraintsChanges).isNull()
+ with(largeScreenConstraint) {
+ assertThat(getConstraint(R.id.begin_guide).layout.guideBegin)
+ .isEqualTo(cutoutStart - padding)
+ assertThat(getConstraint(R.id.end_guide).layout.guideEnd)
+ .isEqualTo(cutoutEnd - padding)
+ }
}
@Test
@@ -246,7 +252,10 @@ class CombinedShadeHeaderConstraintsTest : SysuiTestCase() {
assertThat(getConstraint(R.id.end_guide).layout.guideEnd).isEqualTo(0)
}
- assertThat(changes.largeScreenConstraintsChanges).isNull()
+ with(largeScreenConstraint) {
+ assertThat(getConstraint(R.id.begin_guide).layout.guideBegin).isEqualTo(0)
+ assertThat(getConstraint(R.id.end_guide).layout.guideEnd).isEqualTo(0)
+ }
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index 3e769e94b6ad..76aa08a1b92a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.tuner.TunerService
import com.android.systemui.tuner.TunerService.Tunable
@@ -69,6 +70,8 @@ class PulsingGestureListenerTest : SysuiTestCase() {
private lateinit var statusBarStateController: StatusBarStateController
@Mock
private lateinit var shadeLogger: ShadeLogger
+ @Mock
+ private lateinit var userTracker: UserTracker
private lateinit var tunableCaptor: ArgumentCaptor<Tunable>
private lateinit var underTest: PulsingGestureListener
@@ -85,6 +88,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
ambientDisplayConfiguration,
statusBarStateController,
shadeLogger,
+ userTracker,
tunerService,
dumpManager
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
new file mode 100644
index 000000000000..5fb1e79e93e8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.smartspace
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.smartspace.config.BcSmartspaceConfigProvider
+import com.android.systemui.util.mockito.whenever
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BcSmartspaceConfigProviderTest : SysuiTestCase() {
+ @Mock private lateinit var featureFlags: FeatureFlags
+
+ private lateinit var configProvider: BcSmartspaceConfigProvider
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ configProvider = BcSmartspaceConfigProvider(featureFlags)
+ }
+
+ @Test
+ fun isDefaultDateWeatherDisabled_flagIsTrue_returnsTrue() {
+ whenever(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
+
+ assertTrue(configProvider.isDefaultDateWeatherDisabled)
+ }
+
+ @Test
+ fun isDefaultDateWeatherDisabled_flagIsFalse_returnsFalse() {
+ whenever(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(false)
+
+ assertFalse(configProvider.isDefaultDateWeatherDisabled)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
index 001e1f4d8086..c5432c5fe330 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -27,6 +27,7 @@ import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dreams.smartspace.DreamSmartspaceController
+import com.android.systemui.plugins.BcSmartspaceConfigPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
import com.android.systemui.plugins.FalsingManager
@@ -94,6 +95,8 @@ class DreamSmartspaceControllerTest : SysuiTestCase() {
private class TestView(context: Context?) : View(context), SmartspaceView {
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {}
+ override fun registerConfigProvider(plugin: BcSmartspaceConfigPlugin?) {}
+
override fun setPrimaryTextColor(color: Int) {}
override fun setIsDreaming(isDreaming: Boolean) {}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index ddcf59ec001f..4bcb54ddbbc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -36,6 +36,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.BcSmartspaceConfigPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
@@ -115,6 +116,9 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
private lateinit var plugin: BcSmartspaceDataPlugin
@Mock
+ private lateinit var configPlugin: BcSmartspaceConfigPlugin
+
+ @Mock
private lateinit var controllerListener: SmartspaceTargetListener
@Captor
@@ -209,7 +213,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
executor,
bgExecutor,
handler,
- Optional.of(plugin)
+ Optional.of(plugin),
+ Optional.of(configPlugin),
)
verify(deviceProvisionedController).addCallback(capture(deviceProvisionedCaptor))
@@ -520,6 +525,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
verify(smartspaceManager, never()).createSmartspaceSession(any())
verify(smartspaceView2).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
verify(smartspaceView2).registerDataProvider(plugin)
+ verify(smartspaceView2).registerConfigProvider(configPlugin)
}
@Test
@@ -557,6 +563,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
verify(smartspaceView).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
verify(smartspaceView).registerDataProvider(plugin)
+ verify(smartspaceView).registerConfigProvider(configPlugin)
verify(smartspaceSession)
.addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor))
sessionListener = sessionListenerCaptor.value
@@ -638,6 +645,9 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
}
+ override fun registerConfigProvider(plugin: BcSmartspaceConfigPlugin?) {
+ }
+
override fun setPrimaryTextColor(color: Int) {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 09f8a10f88c7..a8690388c3e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -39,7 +39,6 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@@ -137,7 +136,6 @@ public class ShadeListBuilderTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
allowTestableLooperAsMainThread();
- when(mNotifPipelineFlags.isStabilityIndexFixEnabled()).thenReturn(true);
mListBuilder = new ShadeListBuilder(
mDumpManager,
@@ -1998,29 +1996,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
@Test
- public void testActiveOrdering_withLegacyStability() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(false);
- assertOrder("ABCDEFG", "ABCDEFG", "ABCDEFG", true); // no change
- assertOrder("ABCDEFG", "ACDEFXBG", "ACDEFXBG", true); // X
- assertOrder("ABCDEFG", "ACDEFBG", "ACDEFBG", true); // no change
- assertOrder("ABCDEFG", "ACDEFBXZG", "ACDEFBXZG", true); // Z and X
- assertOrder("ABCDEFG", "AXCDEZFBG", "AXCDEZFBG", true); // Z and X + gap
- }
-
- @Test
- public void testStableOrdering_withLegacyStability() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(false);
- mStabilityManager.setAllowEntryReordering(false);
- assertOrder("ABCDEFG", "ABCDEFG", "ABCDEFG", true); // no change
- assertOrder("ABCDEFG", "ACDEFXBG", "XABCDEFG", false); // X
- assertOrder("ABCDEFG", "ACDEFBG", "ABCDEFG", false); // no change
- assertOrder("ABCDEFG", "ACDEFBXZG", "XZABCDEFG", false); // Z and X
- assertOrder("ABCDEFG", "AXCDEZFBG", "XZABCDEFG", false); // Z and X + gap
- }
-
- @Test
public void testStableOrdering() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(true);
mStabilityManager.setAllowEntryReordering(false);
// No input or output
assertOrder("", "", "", true);
@@ -2076,7 +2052,6 @@ public class ShadeListBuilderTest extends SysuiTestCase {
@Test
public void testActiveOrdering() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(true);
assertOrder("ABCDEFG", "ACDEFXBG", "ACDEFXBG", true); // X
assertOrder("ABCDEFG", "ACDEFBG", "ACDEFBG", true); // no change
assertOrder("ABCDEFG", "ACDEFBXZG", "ACDEFBXZG", true); // Z and X
@@ -2133,7 +2108,6 @@ public class ShadeListBuilderTest extends SysuiTestCase {
@Test
public void stableOrderingDisregardedWithSectionChange() {
- when(mNotifPipelineFlags.isSemiStableSortEnabled()).thenReturn(true);
// GIVEN the first sectioner's packages can be changed from run-to-run
List<String> mutableSectionerPackages = new ArrayList<>();
mutableSectionerPackages.add(PACKAGE_1);
@@ -2229,49 +2203,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
@Test
- public void groupRevertingToSummaryDoesNotRetainStablePositionWithLegacyIndexLogic() {
- when(mNotifPipelineFlags.isStabilityIndexFixEnabled()).thenReturn(false);
-
- // GIVEN a notification group is on screen
- mStabilityManager.setAllowEntryReordering(false);
-
- // WHEN the list is originally built with reordering disabled (and section changes allowed)
- addNotif(0, PACKAGE_1).setRank(2);
- addNotif(1, PACKAGE_1).setRank(3);
- addGroupSummary(2, PACKAGE_1, "group").setRank(4);
- addGroupChild(3, PACKAGE_1, "group").setRank(5);
- addGroupChild(4, PACKAGE_1, "group").setRank(6);
- dispatchBuild();
-
- verifyBuiltList(
- notif(0),
- notif(1),
- group(
- summary(2),
- child(3),
- child(4)
- )
- );
-
- // WHEN the notification summary rank increases and children removed
- setNewRank(notif(2).entry, 1);
- mEntrySet.remove(4);
- mEntrySet.remove(3);
- dispatchBuild();
-
- // VERIFY the summary (incorrectly) moves to the top of the section where it is ranked,
- // despite visual stability being active
- verifyBuiltList(
- notif(2),
- notif(0),
- notif(1)
- );
- }
-
- @Test
public void groupRevertingToSummaryRetainsStablePosition() {
- when(mNotifPipelineFlags.isStabilityIndexFixEnabled()).thenReturn(true);
-
// GIVEN a notification group is on screen
mStabilityManager.setAllowEntryReordering(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index be6b1dc8e4a4..2686238c0d3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -321,7 +321,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
val testDispatcher = UnconfinedTestDispatcher()
val testScope = TestScope(testDispatcher)
val fakeSettings = FakeSettings().apply {
- putBool(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, true)
+ putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
}
val seenNotificationsProvider = SeenNotificationsProviderImpl()
val keyguardCoordinator =
@@ -372,14 +372,14 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
var showOnlyUnseenNotifsOnKeyguardSetting: Boolean
get() =
- fakeSettings.getBoolForUser(
+ fakeSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
UserHandle.USER_CURRENT,
- )
+ ) == 1
set(value) {
- fakeSettings.putBoolForUser(
+ fakeSettings.putIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
- value,
+ if (value) 1 else 2,
UserHandle.USER_CURRENT,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 601771d64046..03af527eb9f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -41,6 +41,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
@@ -59,6 +60,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -107,6 +109,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
UiEventLoggerFake mUiEventLoggerFake;
@Mock
PendingIntent mPendingIntent;
+ @Mock
+ UserTracker mUserTracker;
private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@@ -114,6 +118,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(false);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
mUiEventLoggerFake = new UiEventLoggerFake();
@@ -131,7 +136,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
mMockHandler,
mFlags,
mKeyguardNotificationVisibilityProvider,
- mUiEventLoggerFake);
+ mUiEventLoggerFake,
+ mUserTracker);
mNotifInterruptionStateProvider.mUseHeadsUp = true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 9d531a165f1f..4559a23a4f5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -44,16 +44,23 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.NotificationChannel;
import android.graphics.Color;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.DisplayMetrics;
import android.view.View;
+import android.widget.ImageView;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.internal.widget.CachingIconView;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
@@ -61,6 +68,7 @@ import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import org.junit.Assert;
@@ -72,6 +80,7 @@ import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.Arrays;
import java.util.List;
@SmallTest
@@ -96,6 +105,9 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
mDependency,
TestableLooper.get(this));
mNotificationTestHelper.setDefaultInflationFlags(FLAG_CONTENT_VIEW_ALL);
+ FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags();
+ fakeFeatureFlags.set(Flags.NOTIFICATION_ANIMATE_BIG_PICTURE, true);
+ mNotificationTestHelper.setFeatureFlags(fakeFeatureFlags);
// create a standard private notification row
Notification normalNotif = mNotificationTestHelper.createNotification();
normalNotif.publicVersion = null;
@@ -559,4 +571,123 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
Assert.assertEquals(1f, mGroupRow.getBottomRoundness(), 0.001f);
Assert.assertEquals(1f, mGroupRow.getChildrenContainer().getBottomRoundness(), 0.001f);
}
+
+ @Test
+ public void testSetContentAnimationRunning_Run() throws Exception {
+ // Create views for the notification row.
+ NotificationContentView publicLayout = mock(NotificationContentView.class);
+ mNotifRow.setPublicLayout(publicLayout);
+ NotificationContentView privateLayout = mock(NotificationContentView.class);
+ mNotifRow.setPrivateLayout(privateLayout);
+
+ mNotifRow.setAnimationRunning(true);
+ verify(publicLayout, times(1)).setContentAnimationRunning(true);
+ verify(privateLayout, times(1)).setContentAnimationRunning(true);
+ }
+
+ @Test
+ public void testSetContentAnimationRunning_Stop() {
+ // Create views for the notification row.
+ NotificationContentView publicLayout = mock(NotificationContentView.class);
+ mNotifRow.setPublicLayout(publicLayout);
+ NotificationContentView privateLayout = mock(NotificationContentView.class);
+ mNotifRow.setPrivateLayout(privateLayout);
+
+ mNotifRow.setAnimationRunning(false);
+ verify(publicLayout, times(1)).setContentAnimationRunning(false);
+ verify(privateLayout, times(1)).setContentAnimationRunning(false);
+ }
+
+ @Test
+ public void testSetContentAnimationRunningInGroupChild_Run() {
+ // Creates parent views on mGroupRow.
+ NotificationContentView publicParentLayout = mock(NotificationContentView.class);
+ mGroupRow.setPublicLayout(publicParentLayout);
+ NotificationContentView privateParentLayout = mock(NotificationContentView.class);
+ mGroupRow.setPrivateLayout(privateParentLayout);
+
+ // Create child views on mNotifRow.
+ NotificationContentView publicChildLayout = mock(NotificationContentView.class);
+ mNotifRow.setPublicLayout(publicChildLayout);
+ NotificationContentView privateChildLayout = mock(NotificationContentView.class);
+ mNotifRow.setPrivateLayout(privateChildLayout);
+ when(mNotifRow.isGroupExpanded()).thenReturn(true);
+ setMockChildrenContainer(mGroupRow, mNotifRow);
+
+ mGroupRow.setAnimationRunning(true);
+ verify(publicParentLayout, times(1)).setContentAnimationRunning(true);
+ verify(privateParentLayout, times(1)).setContentAnimationRunning(true);
+ // The child layouts should be started too.
+ verify(publicChildLayout, times(1)).setContentAnimationRunning(true);
+ verify(privateChildLayout, times(1)).setContentAnimationRunning(true);
+ }
+
+
+ @Test
+ public void testSetIconAnimationRunningGroup_Run() {
+ // Create views for a group row.
+ NotificationContentView publicParentLayout = mock(NotificationContentView.class);
+ mGroupRow.setPublicLayout(publicParentLayout);
+ NotificationContentView privateParentLayout = mock(NotificationContentView.class);
+ mGroupRow.setPrivateLayout(privateParentLayout);
+ when(mGroupRow.isGroupExpanded()).thenReturn(true);
+
+ // Sets up mNotifRow as a child ExpandableNotificationRow.
+ NotificationContentView publicChildLayout = mock(NotificationContentView.class);
+ mNotifRow.setPublicLayout(publicChildLayout);
+ NotificationContentView privateChildLayout = mock(NotificationContentView.class);
+ mNotifRow.setPrivateLayout(privateChildLayout);
+ when(mNotifRow.isGroupExpanded()).thenReturn(true);
+
+ NotificationChildrenContainer mockContainer =
+ setMockChildrenContainer(mGroupRow, mNotifRow);
+
+ // Mock the children view wrappers, and give them each an icon.
+ NotificationViewWrapper mockViewWrapper = mock(NotificationViewWrapper.class);
+ when(mockContainer.getNotificationViewWrapper()).thenReturn(mockViewWrapper);
+ CachingIconView mockIcon = mock(CachingIconView.class);
+ when(mockViewWrapper.getIcon()).thenReturn(mockIcon);
+
+ NotificationViewWrapper mockLowPriorityViewWrapper = mock(NotificationViewWrapper.class);
+ when(mockContainer.getLowPriorityViewWrapper()).thenReturn(mockLowPriorityViewWrapper);
+ CachingIconView mockLowPriorityIcon = mock(CachingIconView.class);
+ when(mockLowPriorityViewWrapper.getIcon()).thenReturn(mockLowPriorityIcon);
+
+ // Give the icon image views drawables, so we can make sure they animate.
+ // We use both AnimationDrawables and AnimatedVectorDrawables to ensure both work.
+ AnimationDrawable drawable = mock(AnimationDrawable.class);
+ AnimatedVectorDrawable vectorDrawable = mock(AnimatedVectorDrawable.class);
+ setDrawableIconsInImageView(mockIcon, drawable, vectorDrawable);
+
+ AnimationDrawable lowPriDrawable = mock(AnimationDrawable.class);
+ AnimatedVectorDrawable lowPriVectorDrawable = mock(AnimatedVectorDrawable.class);
+ setDrawableIconsInImageView(mockLowPriorityIcon, lowPriDrawable, lowPriVectorDrawable);
+
+ mGroupRow.setAnimationRunning(true);
+ verify(drawable, times(1)).start();
+ verify(vectorDrawable, times(1)).start();
+ verify(lowPriDrawable, times(1)).start();
+ verify(lowPriVectorDrawable, times(1)).start();
+ }
+
+ private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable,
+ Drawable rightIconDrawable) {
+ ImageView iconView = mock(ImageView.class);
+ when(icon.findViewById(com.android.internal.R.id.icon)).thenReturn(iconView);
+ when(iconView.getDrawable()).thenReturn(iconDrawable);
+
+ ImageView rightIconView = mock(ImageView.class);
+ when(icon.findViewById(com.android.internal.R.id.right_icon)).thenReturn(rightIconView);
+ when(rightIconView.getDrawable()).thenReturn(rightIconDrawable);
+ }
+
+ private NotificationChildrenContainer setMockChildrenContainer(
+ ExpandableNotificationRow parentRow, ExpandableNotificationRow childRow) {
+ List<ExpandableNotificationRow> rowList = Arrays.asList(childRow);
+ NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
+ when(mockContainer.getNotificationChildCount()).thenReturn(1);
+ when(mockContainer.getAttachedChildren()).thenReturn(rowList);
+ parentRow.setChildrenContainer(mockContainer);
+ return mockContainer;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java
index 1f92b0a42061..819a75bffc8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
@@ -98,5 +100,16 @@ public class FooterViewTest extends SysuiTestCase {
mView.setSecondaryVisible(true /* visible */, true /* animate */);
}
+
+ @Test
+ public void testSetFooterLabelTextAndIcon() {
+ mView.setFooterLabelTextAndIcon(
+ R.string.unlock_to_see_notif_text,
+ R.drawable.ic_friction_lock_closed);
+ assertThat(mView.findViewById(R.id.manage_text).getVisibility()).isEqualTo(View.GONE);
+ assertThat(mView.findSecondaryView().getVisibility()).isEqualTo(View.GONE);
+ assertThat(mView.findViewById(R.id.unlock_prompt_footer).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 562b4dfb35ef..7b2051da4d15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -34,9 +34,12 @@ import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.statusbar.notification.FeedbackIcon
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,6 +47,7 @@ import org.mockito.Mock
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations.initMocks
@@ -305,6 +309,86 @@ class NotificationContentViewTest : SysuiTestCase() {
assertEquals(0, getMarginBottom(actionListMarginTarget))
}
+ @Test
+ fun onSetAnimationRunning() {
+ // Given: contractedWrapper, enpandedWrapper, and headsUpWrapper being set
+ val mockContracted = mock<NotificationViewWrapper>()
+ val mockExpanded = mock<NotificationViewWrapper>()
+ val mockHeadsUp = mock<NotificationViewWrapper>()
+
+ view.setContractedWrapper(mockContracted)
+ view.setExpandedWrapper(mockExpanded)
+ view.setHeadsUpWrapper(mockHeadsUp)
+
+ // When: we set content animation running.
+ assertTrue(view.setContentAnimationRunning(true))
+
+ // Then: contractedChild, expandedChild, and headsUpChild should have setAnimationsRunning
+ // called on them.
+ verify(mockContracted, times(1)).setAnimationsRunning(true)
+ verify(mockExpanded, times(1)).setAnimationsRunning(true)
+ verify(mockHeadsUp, times(1)).setAnimationsRunning(true)
+
+ // When: we set content animation running true _again_.
+ assertFalse(view.setContentAnimationRunning(true))
+
+ // Then: the children should not have setAnimationRunning called on them again.
+ // Verify counts number of calls so far on the object, so these still register as 1.
+ verify(mockContracted, times(1)).setAnimationsRunning(true)
+ verify(mockExpanded, times(1)).setAnimationsRunning(true)
+ verify(mockHeadsUp, times(1)).setAnimationsRunning(true)
+ }
+
+ @Test
+ fun onSetAnimationStopped() {
+ // Given: contractedWrapper, expandedWrapper, and headsUpWrapper being set
+ val mockContracted = mock<NotificationViewWrapper>()
+ val mockExpanded = mock<NotificationViewWrapper>()
+ val mockHeadsUp = mock<NotificationViewWrapper>()
+
+ view.setContractedWrapper(mockContracted)
+ view.setExpandedWrapper(mockExpanded)
+ view.setHeadsUpWrapper(mockHeadsUp)
+
+ // When: we set content animation running.
+ assertTrue(view.setContentAnimationRunning(true))
+
+ // Then: contractedChild, expandedChild, and headsUpChild should have setAnimationsRunning
+ // called on them.
+ verify(mockContracted).setAnimationsRunning(true)
+ verify(mockExpanded).setAnimationsRunning(true)
+ verify(mockHeadsUp).setAnimationsRunning(true)
+
+ // When: we set content animation running false, the state changes, so the function
+ // returns true.
+ assertTrue(view.setContentAnimationRunning(false))
+
+ // Then: the children have their animations stopped.
+ verify(mockContracted).setAnimationsRunning(false)
+ verify(mockExpanded).setAnimationsRunning(false)
+ verify(mockHeadsUp).setAnimationsRunning(false)
+ }
+
+ @Test
+ fun onSetAnimationInitStopped() {
+ // Given: contractedWrapper, expandedWrapper, and headsUpWrapper being set
+ val mockContracted = mock<NotificationViewWrapper>()
+ val mockExpanded = mock<NotificationViewWrapper>()
+ val mockHeadsUp = mock<NotificationViewWrapper>()
+
+ view.setContractedWrapper(mockContracted)
+ view.setExpandedWrapper(mockExpanded)
+ view.setHeadsUpWrapper(mockHeadsUp)
+
+ // When: we try to stop the animations before they've been started.
+ assertFalse(view.setContentAnimationRunning(false))
+
+ // Then: the children should not have setAnimationRunning called on them again.
+ verify(mockContracted, never()).setAnimationsRunning(false)
+ verify(mockExpanded, never()).setAnimationsRunning(false)
+ verify(mockHeadsUp, never()).setAnimationsRunning(false)
+ }
+
private fun createMockContainingNotification(notificationEntry: NotificationEntry) =
mock<ExpandableNotificationRow>().apply {
whenever(this.entry).thenReturn(notificationEntry)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 728e0265c729..e4fc4d5d54ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -53,6 +53,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.controls.util.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -130,6 +131,7 @@ public class NotificationTestHelper {
public final OnUserInteractionCallback mOnUserInteractionCallback;
public final Runnable mFutureDismissalRunnable;
private @InflationFlag int mDefaultInflationFlags;
+ private FeatureFlags mFeatureFlags;
public NotificationTestHelper(
Context context,
@@ -193,12 +195,17 @@ public class NotificationTestHelper {
mFutureDismissalRunnable = mock(Runnable.class);
when(mOnUserInteractionCallback.registerFutureDismissal(any(), anyInt()))
.thenReturn(mFutureDismissalRunnable);
+ mFeatureFlags = mock(FeatureFlags.class);
}
public void setDefaultInflationFlags(@InflationFlag int defaultInflationFlags) {
mDefaultInflationFlags = defaultInflationFlags;
}
+ public void setFeatureFlags(FeatureFlags featureFlags) {
+ mFeatureFlags = featureFlags;
+ }
+
public ExpandableNotificationRowLogger getMockLogger() {
return mMockLogger;
}
@@ -561,7 +568,8 @@ public class NotificationTestHelper {
mock(NotificationGutsManager.class),
mock(MetricsLogger.class),
mock(SmartReplyConstants.class),
- mock(SmartReplyController.class));
+ mock(SmartReplyController.class),
+ mFeatureFlags);
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
index 509ba4194e5e..8f88501a38f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
@@ -16,11 +16,12 @@
package com.android.systemui.statusbar.notification.row.wrapper;
+import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
import android.app.Notification;
-import android.content.Context;
+import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.testing.AndroidTestingRunner;
@@ -28,11 +29,11 @@ import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
+import com.android.internal.widget.BigPictureNotificationImageView;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -73,4 +74,38 @@ public class NotificationBigPictureTemplateViewWrapperTest extends SysuiTestCase
Notification.EXTRA_LARGE_ICON_BIG, new Bundle());
wrapper.onContentUpdated(mRow);
}
+
+ @Test
+ public void setAnimationsRunning_Run() {
+ BigPictureNotificationImageView imageView = mView.findViewById(R.id.big_picture);
+ AnimatedImageDrawable mockDrawable = mock(AnimatedImageDrawable.class);
+
+ assertNotNull(imageView);
+ imageView.setImageDrawable(mockDrawable);
+
+ NotificationViewWrapper wrapper = new NotificationBigPictureTemplateViewWrapper(mContext,
+ mView, mRow);
+ // Required to re-initialize the imageView to the imageView created above.
+ wrapper.onContentUpdated(mRow);
+
+ wrapper.setAnimationsRunning(true);
+ verify(mockDrawable).start();
+ }
+
+ @Test
+ public void setAnimationsRunning_Stop() {
+ BigPictureNotificationImageView imageView = mView.findViewById(R.id.big_picture);
+ AnimatedImageDrawable mockDrawable = mock(AnimatedImageDrawable.class);
+
+ assertNotNull(imageView);
+ imageView.setImageDrawable(mockDrawable);
+
+ NotificationViewWrapper wrapper = new NotificationBigPictureTemplateViewWrapper(mContext,
+ mView, mRow);
+ // Required to re-initialize the imageView to the imageView created above.
+ wrapper.onContentUpdated(mRow);
+
+ wrapper.setAnimationsRunning(false);
+ verify(mockDrawable).stop();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
new file mode 100644
index 000000000000..3fa68bb69da2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row.wrapper
+
+import android.graphics.drawable.AnimatedImageDrawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.internal.widget.CachingIconView
+import com.android.internal.widget.ConversationLayout
+import com.android.internal.widget.MessagingGroup
+import com.android.internal.widget.MessagingImageMessage
+import com.android.internal.widget.MessagingLinearLayout
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class NotificationConversationTemplateViewWrapperTest : SysuiTestCase() {
+
+ private lateinit var mRow: ExpandableNotificationRow
+ private lateinit var helper: NotificationTestHelper
+
+ @Before
+ fun setUp() {
+ allowTestableLooperAsMainThread()
+ helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+ mRow = helper.createRow()
+ }
+
+ @Test
+ fun setAnimationsRunning_Run() {
+ // Creates a mocked out NotificationEntry of ConversationLayout type,
+ // with a mock imageMessage.drawable embedded in its MessagingImageMessages
+ // (both top level, and in a group).
+ val mockDrawable = mock<AnimatedImageDrawable>()
+ val mockDrawable2 = mock<AnimatedImageDrawable>()
+ val mockLayoutView: View = fakeConversationLayout(mockDrawable, mockDrawable2)
+
+ val wrapper: NotificationViewWrapper =
+ NotificationConversationTemplateViewWrapper(mContext, mockLayoutView, mRow)
+ wrapper.onContentUpdated(mRow)
+ wrapper.setAnimationsRunning(true)
+
+ // Verifies that each AnimatedImageDrawable is started animating.
+ verify(mockDrawable).start()
+ verify(mockDrawable2).start()
+ }
+
+ @Test
+ fun setAnimationsRunning_Stop() {
+ // Creates a mocked out NotificationEntry of ConversationLayout type,
+ // with a mock imageMessage.drawable embedded in its MessagingImageMessages
+ // (both top level, and in a group).
+ val mockDrawable = mock<AnimatedImageDrawable>()
+ val mockDrawable2 = mock<AnimatedImageDrawable>()
+ val mockLayoutView: View = fakeConversationLayout(mockDrawable, mockDrawable2)
+
+ val wrapper: NotificationViewWrapper =
+ NotificationConversationTemplateViewWrapper(mContext, mockLayoutView, mRow)
+ wrapper.onContentUpdated(mRow)
+ wrapper.setAnimationsRunning(false)
+
+ // Verifies that each AnimatedImageDrawable is started animating.
+ verify(mockDrawable).stop()
+ verify(mockDrawable2).stop()
+ }
+
+ private fun fakeConversationLayout(
+ mockDrawableGroupMessage: AnimatedImageDrawable,
+ mockDrawableImageMessage: AnimatedImageDrawable
+ ): View {
+ val mockMessagingImageMessage: MessagingImageMessage =
+ mock<MessagingImageMessage>().apply {
+ whenever(drawable).thenReturn(mockDrawableImageMessage)
+ }
+ val mockImageMessageContainer: MessagingLinearLayout =
+ mock<MessagingLinearLayout>().apply {
+ whenever(childCount).thenReturn(1)
+ whenever(getChildAt(any())).thenReturn(mockMessagingImageMessage)
+ }
+
+ val mockMessagingImageMessageForGroup: MessagingImageMessage =
+ mock<MessagingImageMessage>().apply {
+ whenever(drawable).thenReturn(mockDrawableGroupMessage)
+ }
+ val mockMessageContainer: MessagingLinearLayout =
+ mock<MessagingLinearLayout>().apply {
+ whenever(childCount).thenReturn(1)
+ whenever(getChildAt(any())).thenReturn(mockMessagingImageMessageForGroup)
+ }
+ val mockGroup: MessagingGroup =
+ mock<MessagingGroup>().apply {
+ whenever(messageContainer).thenReturn(mockMessageContainer)
+ }
+ val mockView: View =
+ mock<ConversationLayout>().apply {
+ whenever(messagingGroups).thenReturn(ArrayList<MessagingGroup>(listOf(mockGroup)))
+ whenever(imageMessageContainer).thenReturn(mockImageMessageContainer)
+ whenever(messagingLinearLayout).thenReturn(mockMessageContainer)
+
+ // These must be mocked as they're required to be nonnull.
+ whenever(requireViewById<View>(R.id.conversation_icon_container)).thenReturn(mock())
+ whenever(requireViewById<CachingIconView>(R.id.conversation_icon))
+ .thenReturn(mock())
+ whenever(findViewById<CachingIconView>(R.id.icon)).thenReturn(mock())
+ whenever(requireViewById<View>(R.id.conversation_icon_badge_bg)).thenReturn(mock())
+ whenever(requireViewById<View>(R.id.expand_button)).thenReturn(mock())
+ whenever(requireViewById<View>(R.id.expand_button_container)).thenReturn(mock())
+ whenever(requireViewById<View>(R.id.conversation_icon_badge_ring))
+ .thenReturn(mock())
+ whenever(requireViewById<View>(R.id.app_name_text)).thenReturn(mock())
+ whenever(requireViewById<View>(R.id.conversation_text)).thenReturn(mock())
+ }
+ return mockView
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
new file mode 100644
index 000000000000..c0444b563a2c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row.wrapper
+
+import android.graphics.drawable.AnimatedImageDrawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.widget.MessagingGroup
+import com.android.internal.widget.MessagingImageMessage
+import com.android.internal.widget.MessagingLayout
+import com.android.internal.widget.MessagingLinearLayout
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class NotificationMessagingTemplateViewWrapperTest : SysuiTestCase() {
+
+ private lateinit var mRow: ExpandableNotificationRow
+ private lateinit var helper: NotificationTestHelper
+
+ @Before
+ fun setUp() {
+ allowTestableLooperAsMainThread()
+ helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+ mRow = helper.createRow()
+ }
+
+ @Test
+ fun setAnimationsRunning_Run() {
+ // Creates a mocked out NotificationEntry of MessagingLayout/MessagingStyle type,
+ // with a mock imageMessage.drawable embedded in its MessagingImageMessage.
+ val mockDrawable = mock<AnimatedImageDrawable>()
+ val mockLayoutView: View = fakeMessagingLayout(mockDrawable)
+
+ val wrapper: NotificationViewWrapper =
+ NotificationMessagingTemplateViewWrapper(mContext, mockLayoutView, mRow)
+ wrapper.setAnimationsRunning(true)
+
+ // Verifies that each AnimatedImageDrawable is started animating.
+ verify(mockDrawable).start()
+ }
+
+ @Test
+ fun setAnimationsRunning_Stop() {
+ // Creates a mocked out NotificationEntry of MessagingLayout/MessagingStyle type,
+ // with a mock imageMessage.drawable embedded in its MessagingImageMessage.
+ val mockDrawable = mock<AnimatedImageDrawable>()
+ val mockLayoutView: View = fakeMessagingLayout(mockDrawable)
+
+ val wrapper: NotificationViewWrapper =
+ NotificationMessagingTemplateViewWrapper(mContext, mockLayoutView, mRow)
+ wrapper.setAnimationsRunning(false)
+
+ // Verifies that each AnimatedImageDrawable is started animating.
+ verify(mockDrawable).stop()
+ }
+
+ private fun fakeMessagingLayout(mockDrawable: AnimatedImageDrawable): View {
+ val mockMessagingImageMessage: MessagingImageMessage =
+ mock<MessagingImageMessage>().apply { whenever(drawable).thenReturn(mockDrawable) }
+ val mockMessageContainer: MessagingLinearLayout =
+ mock<MessagingLinearLayout>().apply {
+ whenever(childCount).thenReturn(1)
+ whenever(getChildAt(any())).thenReturn(mockMessagingImageMessage)
+ }
+ val mockGroup: MessagingGroup =
+ mock<MessagingGroup>().apply {
+ whenever(messageContainer).thenReturn(mockMessageContainer)
+ }
+ val mockView: View =
+ mock<MessagingLayout>().apply {
+ whenever(messagingGroups).thenReturn(ArrayList<MessagingGroup>(listOf(mockGroup)))
+ }
+ return mockView
+ }
+}
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 645052feee94..9f6f082d07c4 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
@@ -21,6 +21,7 @@ import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -65,6 +66,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl;
import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
+import com.android.systemui.statusbar.notification.collection.render.NotifStats;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -78,6 +80,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
import org.junit.Test;
@@ -135,10 +138,14 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private ShadeTransitionController mShadeTransitionController;
@Mock private FeatureFlags mFeatureFlags;
@Mock private NotificationTargetsHelper mNotificationTargetsHelper;
+ @Mock private SecureSettings mSecureSettings;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
+ private final SeenNotificationsProviderImpl mSeenNotificationsProvider =
+ new SeenNotificationsProviderImpl();
+
private NotificationStackScrollLayoutController mController;
@Before
@@ -180,14 +187,15 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mUiEventLogger,
mRemoteInputManager,
mVisibilityLocationProviderDelegator,
- new SeenNotificationsProviderImpl(),
+ mSeenNotificationsProvider,
mShadeController,
mJankMonitor,
mStackLogger,
mLogger,
mNotificationStackSizeCalculator,
mFeatureFlags,
- mNotificationTargetsHelper
+ mNotificationTargetsHelper,
+ mSecureSettings
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
@@ -233,16 +241,14 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
- /* notifVisibleInShade= */ true,
- /* areSeenNotifsFiltered= */false);
+ /* notifVisibleInShade= */ true);
setupShowEmptyShadeViewState(false);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ false,
- /* notifVisibleInShade= */ true,
- /* areSeenNotifsFiltered= */false);
+ /* notifVisibleInShade= */ true);
}
@Test
@@ -255,16 +261,14 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
- /* notifVisibleInShade= */ false,
- /* areSeenNotifsFiltered= */false);
+ /* notifVisibleInShade= */ false);
setupShowEmptyShadeViewState(false);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ false,
- /* notifVisibleInShade= */ false,
- /* areSeenNotifsFiltered= */false);
+ /* notifVisibleInShade= */ false);
}
@Test
@@ -283,16 +287,14 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
- /* notifVisibleInShade= */ false,
- /* areSeenNotifsFiltered= */false);
+ /* notifVisibleInShade= */ false);
mController.setQsFullScreen(true);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
- /* notifVisibleInShade= */ false,
- /* areSeenNotifsFiltered= */false);
+ /* notifVisibleInShade= */ false);
}
@Test
@@ -400,6 +402,17 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
verify(mNotificationStackScrollLayout).setIsRemoteInputActive(true);
}
+ @Test
+ public void testSetNotifStats_updatesHasFilteredOutSeenNotifications() {
+ when(mNotifPipelineFlags.getShouldFilterUnseenNotifsOnKeyguard()).thenReturn(true);
+ mSeenNotificationsProvider.setHasFilteredOutSeenNotifications(true);
+ mController.attach(mNotificationStackScrollLayout);
+ mController.getNotifStackController().setNotifStats(NotifStats.getEmpty());
+ verify(mNotificationStackScrollLayout).setHasFilteredOutSeenNotifications(true);
+ verify(mNotificationStackScrollLayout).updateFooter();
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(anyBoolean(), anyBoolean());
+ }
+
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 7622549d29de..dd7143ae7e16 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
@@ -30,6 +30,7 @@ import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -53,6 +54,7 @@ import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.TextView;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
@@ -328,7 +330,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void updateEmptyView_dndSuppressing() {
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true, true, false);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -338,7 +340,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true, false, false);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
}
@@ -347,10 +349,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void updateEmptyView_noNotificationsToDndSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true, false, false);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
- mStackScroller.updateEmptyShadeView(true, true, false);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -818,6 +820,29 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
assertEquals(0f, mAmbientState.getStackY());
}
+ @Test
+ public void hasFilteredOutSeenNotifs_updateFooter() {
+ mStackScroller.setCurrentUserSetup(true);
+
+ // add footer
+ mStackScroller.inflateFooterView();
+ TextView footerLabel =
+ mStackScroller.mFooterView.requireViewById(R.id.unlock_prompt_footer);
+
+ mStackScroller.setHasFilteredOutSeenNotifications(true);
+ mStackScroller.updateFooter();
+
+ assertThat(footerLabel.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void hasFilteredOutSeenNotifs_updateEmptyShadeView() {
+ mStackScroller.setHasFilteredOutSeenNotifications(true);
+ mStackScroller.updateEmptyShadeView(true, false);
+
+ verify(mEmptyShadeView).setFooterText(not(0));
+ }
+
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/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index 3fccd37d9d7e..b879cf24fcf1 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
@@ -25,8 +25,10 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.os.PowerManager;
+import android.os.UserHandle;
import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
import android.view.InsetsVisibilities;
@@ -41,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.settings.UserTracker;
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeController;
@@ -88,6 +91,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
@Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
@Mock private SystemBarAttributesListener mSystemBarAttributesListener;
@Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
+ @Mock private UserTracker mUserTracker;
CentralSurfacesCommandQueueCallbacks mSbcqCallbacks;
@@ -120,8 +124,11 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
new DisableFlagsLogger(),
DEFAULT_DISPLAY,
mSystemBarAttributesListener,
- mCameraLauncherLazy);
+ mCameraLauncherLazy,
+ mUserTracker);
+ when(mUserTracker.getUserHandle()).thenReturn(
+ UserHandle.of(ActivityManager.getCurrentUser()));
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
when(mRemoteInputQuickSettingsDisabler.adjustDisableFlags(anyInt()))
.thenAnswer((Answer<Integer>) invocation -> invocation.getArgument(0));
@@ -140,7 +147,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
// Trying to open it does nothing.
mSbcqCallbacks.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController, never()).expandWithoutQs();
+ verify(mNotificationPanelViewController, never()).expandShadeToNotifications();
mSbcqCallbacks.animateExpandSettingsPanel(null);
verify(mNotificationPanelViewController, never()).expand(anyBoolean());
}
@@ -158,7 +165,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
// Can now be opened.
mSbcqCallbacks.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController).expandWithoutQs();
+ verify(mNotificationPanelViewController).expandShadeToNotifications();
mSbcqCallbacks.animateExpandSettingsPanel(null);
verify(mNotificationPanelViewController).expandWithQs();
}
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 4c1b219af843..b1363a047307 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
@@ -44,6 +44,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.IWallpaperManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -118,6 +119,7 @@ import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.NotificationPanelView;
@@ -306,6 +308,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
*/
@Mock private ViewRootImpl mViewRootImpl;
@Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
+ @Mock private UserTracker mUserTracker;
@Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
@Mock IPowerManager mPowerManagerService;
@@ -321,6 +324,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
+ // CentralSurfacesImpl's runtime flag check fails if the flag is absent.
+ // This value is unused, because test manifest is opted in.
+ mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
+
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
Handler.createAsync(Looper.myLooper()));
@@ -338,7 +345,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
new Handler(TestableLooper.get(this).getLooper()),
mock(NotifPipelineFlags.class),
mock(KeyguardNotificationVisibilityProvider.class),
- mock(UiEventLogger.class));
+ mock(UiEventLogger.class),
+ mUserTracker);
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -419,6 +427,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
+ when(mUserTracker.getUserHandle()).thenReturn(
+ UserHandle.of(ActivityManager.getCurrentUser()));
mCentralSurfaces = new CentralSurfacesImpl(
mContext,
@@ -508,7 +519,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mDreamManager,
mCameraLauncherLazy,
() -> mLightRevealScrimViewModel,
- mAlternateBouncerInteractor
+ mAlternateBouncerInteractor,
+ mUserTracker
) {
@Override
protected ViewRootImpl getViewRootImpl() {
@@ -1280,7 +1292,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
Handler mainHandler,
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker) {
super(
contentResolver,
powerManager,
@@ -1294,7 +1307,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mainHandler,
flags,
keyguardNotificationVisibilityProvider,
- uiEventLogger
+ uiEventLogger,
+ userTracker
);
mUseHeadsUp = true;
}
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 c8438501b3e6..eb5edbc21d89 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
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.content.res.Resources;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
@@ -44,6 +45,7 @@ import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -82,6 +84,7 @@ public class DozeParametersTest extends SysuiTestCase {
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private ConfigurationController mConfigurationController;
+ @Mock private UserTracker mUserTracker;
@Captor private ArgumentCaptor<BatteryStateChangeCallback> mBatteryStateChangeCallback;
/**
@@ -107,6 +110,7 @@ public class DozeParametersTest extends SysuiTestCase {
when(mSysUIUnfoldComponent.getFoldAodAnimationController())
.thenReturn(mFoldAodAnimationController);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
mDozeParameters = new DozeParameters(
mContext,
@@ -123,7 +127,8 @@ public class DozeParametersTest extends SysuiTestCase {
mUnlockedScreenOffAnimationController,
mKeyguardUpdateMonitor,
mConfigurationController,
- mStatusBarStateController
+ mStatusBarStateController,
+ mUserTracker
);
verify(mBatteryController).addCallback(mBatteryStateChangeCallback.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 7ad9cc27982a..2f495355df40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -58,8 +58,8 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Assert;
@@ -87,7 +87,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Mock
private KeyguardHostViewController mKeyguardHostViewController;
@Mock
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mExpansionCallback;
+ private PrimaryBouncerExpansionCallback mExpansionCallback;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
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 64dee956fcc1..305b9fea7569 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
@@ -31,6 +31,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.BluetoothController
import com.android.systemui.statusbar.policy.CastController
@@ -71,61 +72,37 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
private const val ALARM_SLOT = "alarm"
}
- @Mock
- private lateinit var iconController: StatusBarIconController
- @Mock
- private lateinit var commandQueue: CommandQueue
- @Mock
- private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock
- private lateinit var castController: CastController
- @Mock
- private lateinit var hotspotController: HotspotController
- @Mock
- private lateinit var bluetoothController: BluetoothController
- @Mock
- private lateinit var nextAlarmController: NextAlarmController
- @Mock
- private lateinit var userInfoController: UserInfoController
- @Mock
- private lateinit var rotationLockController: RotationLockController
- @Mock
- private lateinit var dataSaverController: DataSaverController
- @Mock
- private lateinit var zenModeController: ZenModeController
- @Mock
- private lateinit var deviceProvisionedController: DeviceProvisionedController
- @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 devicePolicyManager: DevicePolicyManager
- @Mock
- private lateinit var recordingController: RecordingController
- @Mock
- private lateinit var telecomManager: TelecomManager
- @Mock
- private lateinit var sharedPreferences: SharedPreferences
- @Mock
- private lateinit var dateFormatUtil: DateFormatUtil
+ @Mock private lateinit var iconController: StatusBarIconController
+ @Mock private lateinit var commandQueue: CommandQueue
+ @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var castController: CastController
+ @Mock private lateinit var hotspotController: HotspotController
+ @Mock private lateinit var bluetoothController: BluetoothController
+ @Mock private lateinit var nextAlarmController: NextAlarmController
+ @Mock private lateinit var userInfoController: UserInfoController
+ @Mock private lateinit var rotationLockController: RotationLockController
+ @Mock private lateinit var dataSaverController: DataSaverController
+ @Mock private lateinit var zenModeController: ZenModeController
+ @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @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
+ @Mock private lateinit var devicePolicyManager: DevicePolicyManager
+ @Mock private lateinit var recordingController: RecordingController
+ @Mock private lateinit var telecomManager: TelecomManager
+ @Mock private lateinit var sharedPreferences: SharedPreferences
+ @Mock private lateinit var dateFormatUtil: DateFormatUtil
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var ringerModeTracker: RingerModeTracker
- @Mock
- private lateinit var privacyItemController: PrivacyItemController
- @Mock
- private lateinit var privacyLogger: PrivacyLogger
+ @Mock private lateinit var privacyItemController: PrivacyItemController
+ @Mock private lateinit var privacyLogger: PrivacyLogger
@Captor
private lateinit var alarmCallbackCaptor:
- ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
+ ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
private lateinit var executor: FakeExecutor
private lateinit var statusBarPolicy: PhoneStatusBarPolicy
@@ -137,8 +114,8 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
executor = FakeExecutor(FakeSystemClock())
testableLooper = TestableLooper.get(this)
context.orCreateTestableResources.addOverride(
- com.android.internal.R.string.status_bar_alarm_clock,
- ALARM_SLOT
+ com.android.internal.R.string.status_bar_alarm_clock,
+ ALARM_SLOT
)
statusBarPolicy = createStatusBarPolicy()
}
@@ -195,36 +172,37 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
private fun createStatusBarPolicy(): PhoneStatusBarPolicy {
return PhoneStatusBarPolicy(
- iconController,
- commandQueue,
- broadcastDispatcher,
- executor,
- testableLooper.looper,
- context.resources,
- castController,
- hotspotController,
- bluetoothController,
- nextAlarmController,
- userInfoController,
- rotationLockController,
- dataSaverController,
- zenModeController,
- deviceProvisionedController,
- keyguardStateController,
- locationController,
- sensorPrivacyController,
- iActivityManager,
- alarmManager,
- userManager,
- devicePolicyManager,
- recordingController,
- telecomManager,
- /* displayId = */ 0,
- sharedPreferences,
- dateFormatUtil,
- ringerModeTracker,
- privacyItemController,
- privacyLogger
+ iconController,
+ commandQueue,
+ broadcastDispatcher,
+ executor,
+ testableLooper.looper,
+ context.resources,
+ castController,
+ hotspotController,
+ bluetoothController,
+ nextAlarmController,
+ userInfoController,
+ rotationLockController,
+ dataSaverController,
+ zenModeController,
+ deviceProvisionedController,
+ keyguardStateController,
+ locationController,
+ sensorPrivacyController,
+ iActivityManager,
+ alarmManager,
+ userManager,
+ userTracker,
+ devicePolicyManager,
+ recordingController,
+ telecomManager,
+ /* displayId = */ 0,
+ sharedPreferences,
+ dateFormatUtil,
+ ringerModeTracker,
+ privacyItemController,
+ privacyLogger
)
}
}
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 c7a0582f0007..c0537a6dc4cf 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
@@ -630,6 +630,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void transitionToUnlocked() {
+ mScrimController.setClipsQsScrim(false);
mScrimController.setRawPanelExpansionFraction(0f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
finishAnimationsImmediately();
@@ -645,14 +646,21 @@ public class ScrimControllerTest extends SysuiTestCase {
));
// Back scrim should be visible after start dragging
- mScrimController.setRawPanelExpansionFraction(0.3f);
+ mScrimController.setRawPanelExpansionFraction(0.29f);
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, TRANSPARENT,
mScrimBehind, SEMI_TRANSPARENT));
+ // Back scrim should be opaque at 30%
+ mScrimController.setRawPanelExpansionFraction(0.3f);
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
// Then, notification scrim should fade in
- mScrimController.setRawPanelExpansionFraction(0.7f);
+ mScrimController.setRawPanelExpansionFraction(0.31f);
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, SEMI_TRANSPARENT,
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 e3e648a8f716..1ba0a36fb05d 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
@@ -39,6 +39,8 @@ import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
+import android.window.BackEvent;
+import android.window.OnBackAnimationCallback;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.WindowOnBackInvokedDispatcher;
@@ -56,10 +58,12 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.data.BouncerView;
import com.android.systemui.keyguard.data.BouncerViewDelegate;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -120,16 +124,20 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private BouncerView mBouncerView;
@Mock private BouncerViewDelegate mBouncerViewDelegate;
+ @Mock private OnBackAnimationCallback mBouncerViewDelegateBackCallback;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
+ private PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
+ mBouncerExpansionCallback;
private FakeKeyguardStateController mKeyguardStateController =
spy(new FakeKeyguardStateController());
- @Mock private ViewRootImpl mViewRootImpl;
- @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
+ @Mock
+ private ViewRootImpl mViewRootImpl;
+ @Mock
+ private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
@Captor
- private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
+ private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
@Before
@@ -140,6 +148,10 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
.thenReturn(mKeyguardMessageAreaController);
when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
+ when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback);
+ when(mFeatureFlags
+ .isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM))
+ .thenReturn(true);
when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(true);
@@ -183,8 +195,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mNotificationContainer,
mBypassController);
mStatusBarKeyguardViewManager.show(null);
- ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
- ArgumentCaptor.forClass(KeyguardBouncer.PrimaryBouncerExpansionCallback.class);
+ ArgumentCaptor<PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
+ ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
verify(mPrimaryBouncerCallbackInteractor).addBouncerExpansionCallback(
callbackArgumentCaptor.capture());
mBouncerExpansionCallback = callbackArgumentCaptor.getValue();
@@ -193,7 +205,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Test
public void dismissWithAction_AfterKeyguardGoneSetToFalse() {
OnDismissAction action = () -> false;
- Runnable cancelAction = () -> {};
+ Runnable cancelAction = () -> {
+ };
mStatusBarKeyguardViewManager.dismissWithAction(
action, cancelAction, false /* afterKeyguardGone */);
verify(mPrimaryBouncerInteractor).setDismissAction(eq(action), eq(cancelAction));
@@ -541,12 +554,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mBouncerExpansionCallback.onVisibilityChanged(true);
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
- mOnBackInvokedCallback.capture());
+ mBackCallbackCaptor.capture());
/* verify that the same callback is unregistered when the bouncer becomes invisible */
mBouncerExpansionCallback.onVisibilityChanged(false);
verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
- eq(mOnBackInvokedCallback.getValue()));
+ eq(mBackCallbackCaptor.getValue()));
}
@Test
@@ -555,18 +568,63 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
/* capture the predictive back callback during registration */
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
- mOnBackInvokedCallback.capture());
+ mBackCallbackCaptor.capture());
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
/* invoke the back callback directly */
- mOnBackInvokedCallback.getValue().onBackInvoked();
+ mBackCallbackCaptor.getValue().onBackInvoked();
/* verify that the bouncer will be hidden as a result of the invocation */
verify(mCentralSurfaces).setBouncerShowing(eq(false));
}
@Test
+ public void testPredictiveBackCallback_noBackAnimationForFullScreenBouncer() {
+ when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
+ .thenReturn(KeyguardSecurityModel.SecurityMode.SimPin);
+ mBouncerExpansionCallback.onVisibilityChanged(true);
+ /* capture the predictive back callback during registration */
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ mBackCallbackCaptor.capture());
+ assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
+
+ OnBackAnimationCallback backCallback =
+ (OnBackAnimationCallback) mBackCallbackCaptor.getValue();
+
+ BackEvent event = new BackEvent(0, 0, 0, BackEvent.EDGE_LEFT);
+ backCallback.onBackStarted(event);
+ verify(mBouncerViewDelegateBackCallback, never()).onBackStarted(any());
+ }
+
+ @Test
+ public void testPredictiveBackCallback_forwardsBackDispatches() {
+ mBouncerExpansionCallback.onVisibilityChanged(true);
+ /* capture the predictive back callback during registration */
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+ mBackCallbackCaptor.capture());
+ assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
+
+ OnBackAnimationCallback backCallback =
+ (OnBackAnimationCallback) mBackCallbackCaptor.getValue();
+
+ BackEvent event = new BackEvent(0, 0, 0, BackEvent.EDGE_LEFT);
+ backCallback.onBackStarted(event);
+ verify(mBouncerViewDelegateBackCallback).onBackStarted(eq(event));
+
+ backCallback.onBackProgressed(event);
+ verify(mBouncerViewDelegateBackCallback).onBackProgressed(eq(event));
+
+ backCallback.onBackInvoked();
+ verify(mBouncerViewDelegateBackCallback).onBackInvoked();
+
+ backCallback.onBackCancelled();
+ verify(mBouncerViewDelegateBackCallback).onBackCancelled();
+ }
+
+ @Test
public void testReportBouncerOnDreamWhenVisible() {
mBouncerExpansionCallback.onVisibilityChanged(true);
verify(mCentralSurfaces).setBouncerShowingOverDream(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
index 0605b8d43f65..55ab6812da91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
@@ -60,6 +60,7 @@ import com.android.systemui.keyguard.data.BouncerView;
import com.android.systemui.keyguard.data.BouncerViewDelegate;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -126,7 +127,8 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
@Mock private BouncerViewDelegate mBouncerViewDelegate;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
+ private PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
+ mBouncerExpansionCallback;
private FakeKeyguardStateController mKeyguardStateController =
spy(new FakeKeyguardStateController());
@@ -141,7 +143,7 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mKeyguardBouncerFactory.create(
any(ViewGroup.class),
- any(KeyguardBouncer.PrimaryBouncerExpansionCallback.class)))
+ any(PrimaryBouncerExpansionCallback.class)))
.thenReturn(mPrimaryBouncer);
when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer);
when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea);
@@ -189,8 +191,8 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
mNotificationContainer,
mBypassController);
mStatusBarKeyguardViewManager.show(null);
- ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
- ArgumentCaptor.forClass(KeyguardBouncer.PrimaryBouncerExpansionCallback.class);
+ ArgumentCaptor<PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
+ ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
verify(mKeyguardBouncerFactory).create(any(ViewGroup.class),
callbackArgumentCaptor.capture());
mBouncerExpansionCallback = callbackArgumentCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 19658e6398c1..ccc57ad72f36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -59,6 +60,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeControllerImpl;
@@ -139,6 +141,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private ActivityLaunchAnimator mActivityLaunchAnimator;
@Mock
private InteractionJankMonitor mJankMonitor;
+ @Mock
+ private UserTracker mUserTracker;
private final FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private ExpandableNotificationRow mNotificationRow;
private ExpandableNotificationRow mBubbleNotificationRow;
@@ -183,6 +187,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean()))
.thenAnswer(invocation -> NotificationVisibility.obtain(
invocation.<NotificationEntry>getArgument(0).getKey(), 0, 1, false));
+ when(mUserTracker.getUserHandle()).thenReturn(
+ UserHandle.of(ActivityManager.getCurrentUser()));
HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider =
@@ -222,7 +228,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mActivityLaunchAnimator,
notificationAnimationProvider,
mock(LaunchFullScreenIntentProvider.class),
- mock(FeatureFlags.class)
+ mock(FeatureFlags.class),
+ mUserTracker
);
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index d30222f2b462..711e4ac937cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -50,7 +50,9 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.*
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.ArgumentMatchers.nullable
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.eq
@@ -83,7 +85,8 @@ class OngoingCallControllerTest : SysuiTestCase() {
private lateinit var notifCollectionListener: NotifCollectionListener
@Mock private lateinit var mockOngoingCallFlags: OngoingCallFlags
- @Mock private lateinit var mockSwipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler
+ @Mock private lateinit var mockSwipeStatusBarAwayGestureHandler:
+ SwipeStatusBarAwayGestureHandler
@Mock private lateinit var mockOngoingCallListener: OngoingCallListener
@Mock private lateinit var mockActivityStarter: ActivityStarter
@Mock private lateinit var mockIActivityManager: IActivityManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 49d4bdc88c82..0add905e2750 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -26,6 +26,7 @@ import com.android.systemui.log.table.TableLogBuffer
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.util.MobileMappingsProxy
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionsRepository
@@ -56,6 +57,10 @@ class FakeMobileConnectionsRepository(
private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
+ override val activeSubChangedInGroupEvent: MutableSharedFlow<Unit> = MutableSharedFlow()
+
+ private val _defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+ override val defaultDataSubId = _defaultDataSubId
private val _mobileConnectivity = MutableStateFlow(MobileConnectivityModel())
override val defaultMobileNetworkConnectivity = _mobileConnectivity
@@ -81,6 +86,10 @@ class FakeMobileConnectionsRepository(
_subscriptions.value = subs
}
+ fun setDefaultDataSubId(id: Int) {
+ _defaultDataSubId.value = id
+ }
+
fun setMobileConnectivity(model: MobileConnectivityModel) {
_mobileConnectivity.value = model
}
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 9d16b7fe5246..f12d113cfaa8 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
@@ -90,6 +90,14 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
}
@Test
+ fun `connectivity - defaults to connected and validated`() =
+ testScope.runTest {
+ val connectivity = underTest.defaultMobileNetworkConnectivity.value
+ assertThat(connectivity.isConnected).isTrue()
+ assertThat(connectivity.isValidated).isTrue()
+ }
+
+ @Test
fun `network event - create new subscription`() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
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 813b0ed041a7..ae390a0e2959 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
@@ -479,6 +479,35 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
@Test
+ fun testDefaultDataSubId_updatesOnBroadcast() =
+ runBlocking(IMMEDIATE) {
+ var latest: Int? = null
+ val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_2_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_2_ID)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_1_ID)
+
+ job.cancel()
+ }
+
+ @Test
fun mobileConnectivity_default() {
assertThat(underTest.defaultMobileNetworkConnectivity.value)
.isEqualTo(MobileConnectivityModel(isConnected = false, isValidated = false))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index a29146b01668..7aeaa48165aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -40,6 +40,8 @@ class FakeMobileIconInteractor(
)
)
+ override val isConnected = MutableStateFlow(true)
+
private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.THREE_G)
override val networkTypeIconGroup = _iconGroup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 1c0064610c52..172755cb8d61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -23,6 +23,7 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.log.table.TableLogBuffer
+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.util.MobileMappingsProxy
import kotlinx.coroutines.flow.MutableStateFlow
@@ -59,6 +60,9 @@ class FakeMobileIconsInteractor(
override val alwaysShowDataRatIcon = MutableStateFlow(false)
override val alwaysUseCdmaLevel = MutableStateFlow(false)
+ override val defaultDataSubId = MutableStateFlow(DEFAULT_DATA_SUB_ID)
+
+ override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
@@ -77,6 +81,8 @@ class FakeMobileIconsInteractor(
companion object {
val DEFAULT_ICON = TelephonyIcons.G
+ const val DEFAULT_DATA_SUB_ID = 1
+
// Use [MobileMappings] to define some simple definitions
const val THREE_G = NETWORK_TYPE_GSM
const val LTE = NETWORK_TYPE_LTE
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 e6be7f15235b..c42aba5a7dd9 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
@@ -61,8 +61,10 @@ class MobileIconInteractorTest : SysuiTestCase() {
mobileIconsInteractor.activeDataConnectionHasDataEnabled,
mobileIconsInteractor.alwaysShowDataRatIcon,
mobileIconsInteractor.alwaysUseCdmaLevel,
+ mobileIconsInteractor.defaultMobileNetworkConnectivity,
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
+ mobileIconsInteractor.defaultDataSubId,
mobileIconsInteractor.isDefaultConnectionFailed,
connectionRepository,
)
@@ -289,6 +291,30 @@ class MobileIconInteractorTest : SysuiTestCase() {
}
@Test
+ fun `icon group - checks default data`() =
+ runBlocking(IMMEDIATE) {
+ mobileIconsInteractor.defaultDataSubId.value = SUB_1_ID
+ connectionRepository.setConnectionInfo(
+ MobileConnectionModel(
+ resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+ ),
+ )
+
+ var latest: MobileIconGroup? = null
+ val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(TelephonyIcons.THREE_G)
+
+ // Default data sub id changes to something else
+ mobileIconsInteractor.defaultDataSubId.value = 123
+ yield()
+
+ assertThat(latest).isEqualTo(TelephonyIcons.NOT_DEFAULT_DATA)
+
+ job.cancel()
+ }
+
+ @Test
fun alwaysShowDataRatIcon_matchesParent() =
runBlocking(IMMEDIATE) {
var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index b82a58414db9..1b62d5cc15b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -31,11 +31,13 @@ import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.yield
import org.junit.After
import org.junit.Before
@@ -43,13 +45,16 @@ import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
class MobileIconsInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconsInteractor
private lateinit var connectionsRepository: FakeMobileConnectionsRepository
private val userSetupRepository = FakeUserSetupRepository()
private val mobileMappingsProxy = FakeMobileMappingsProxy()
- private val scope = CoroutineScope(IMMEDIATE)
+
+ private val testDispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
@@ -73,7 +78,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
connectionsRepository,
carrierConfigTracker,
userSetupRepository,
- scope
+ testScope.backgroundScope,
)
}
@@ -81,7 +86,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_default() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
@@ -92,7 +97,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
var latest: List<SubscriptionModel>? = null
@@ -105,7 +110,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_3() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -122,7 +127,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_4() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -139,7 +144,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_active_1() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -157,7 +162,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_nonActive_1() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
@@ -175,7 +180,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun activeDataConnection_turnedOn() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
CONNECTION_1.setDataEnabled(true)
var latest: Boolean? = null
val job =
@@ -188,7 +193,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun activeDataConnection_turnedOff() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
CONNECTION_1.setDataEnabled(true)
var latest: Boolean? = null
val job =
@@ -204,7 +209,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun activeDataConnection_invalidSubId() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job =
underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
@@ -220,7 +225,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_connected_validated_notFailed() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
connectionsRepository.setMobileConnectivity(MobileConnectivityModel(true, true))
@@ -233,7 +238,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_notConnected_notValidated_notFailed() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
@@ -247,7 +252,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun failedConnection_connected_notValidated_failed() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
@@ -261,7 +266,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysShowDataRatIcon_configHasTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this)
@@ -277,7 +282,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysShowDataRatIcon_configHasFalse() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this)
@@ -293,7 +298,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysUseCdmaLevel_configHasTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysUseCdmaLevel.onEach { latest = it }.launchIn(this)
@@ -309,7 +314,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
@Test
fun alwaysUseCdmaLevel_configHasFalse() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
var latest: Boolean? = null
val job = underTest.alwaysUseCdmaLevel.onEach { latest = it }.launchIn(this)
@@ -323,8 +328,286 @@ class MobileIconsInteractorTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun `default mobile connectivity - uses repo value`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ var expected = MobileConnectivityModel(isConnected = true, isValidated = true)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ expected = MobileConnectivityModel(isConnected = false, isValidated = true)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ expected = MobileConnectivityModel(isConnected = true, isValidated = false)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ expected = MobileConnectivityModel(isConnected = false, isValidated = false)
+ connectionsRepository.setMobileConnectivity(expected)
+ assertThat(latest).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - in same group - validated matches previous value`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+ // Trigger a data change in the same subscription group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - in same group - validated matches previous value - expires after 2s`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+ // Trigger a data change in the same subscription group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+ // After 1s, the force validation bit is still present
+ advanceTimeBy(1000)
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ // After 2s, the force validation expires
+ advanceTimeBy(1001)
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - in same group - not validated - uses new value immediately`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = false,
+ )
+ )
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - lose validation - then switch happens - clears forced bit`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ // GIVEN the network starts validated
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+
+ // WHEN a data change happens in the same group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+ // WHEN the validation bit is lost
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ // WHEN another data change happens in the same group
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+ // THEN the forced validation bit is still removed after 2s
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ advanceTimeBy(1000)
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ advanceTimeBy(1001)
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - while already forcing validation - resets clock`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+ advanceTimeBy(1000)
+
+ // WHEN another change in same group event happens
+ connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ // THEN the forced validation remains for exactly 2 more seconds from now
+
+ // 1.500s from second event
+ advanceTimeBy(1500)
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = true,
+ )
+ )
+
+ // 2.001s from the second event
+ advanceTimeBy(501)
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `data switch - not in same group - uses new values`() =
+ testScope.runTest {
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = true,
+ isValidated = true,
+ )
+ )
+ connectionsRepository.setMobileConnectivity(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ assertThat(latest)
+ .isEqualTo(
+ MobileConnectivityModel(
+ isConnected = false,
+ isValidated = false,
+ )
+ )
+
+ job.cancel()
+ }
+
companion object {
- private val IMMEDIATE = Dispatchers.Main.immediate
private val tableLogBuffer =
TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index 2a8d42ff6997..a24e29aebc1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -274,6 +274,41 @@ class MobileIconViewModelTest : SysuiTestCase() {
}
@Test
+ fun `network type - alwaysShow - shown when not connected`() =
+ testScope.runTest {
+ interactor.setIconGroup(THREE_G)
+ interactor.isConnected.value = false
+ interactor.alwaysShowDataRatIcon.value = true
+
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ val expected =
+ Icon.Resource(
+ THREE_G.dataType,
+ ContentDescription.Resource(THREE_G.dataContentDescription)
+ )
+ assertThat(latest).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `network type - not shown when not connected`() =
+ testScope.runTest {
+ interactor.setIconGroup(THREE_G)
+ interactor.isDataConnected.value = true
+ interactor.isConnected.value = false
+
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
fun roaming() =
testScope.runTest {
interactor.isRoaming.value = true
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index 99e20124f597..45f7df3c3f5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -159,7 +159,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
underTest.displayView(getState())
assertThat(fakeWakeLock.isHeld).isTrue()
- underTest.removeView("id", "test reason")
+ underTest.removeView(DEFAULT_ID, "test reason")
assertThat(fakeWakeLock.isHeld).isFalse()
}
@@ -175,6 +175,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
@Test
fun displayView_twiceWithDifferentIds_oldViewRemovedNewViewAdded() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "name",
@@ -199,10 +201,15 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
assertThat(windowParamsCaptor.allValues[0].title).isEqualTo("First Fake Window Title")
assertThat(windowParamsCaptor.allValues[1].title).isEqualTo("Second Fake Window Title")
verify(windowManager).removeView(viewCaptor.allValues[0])
+ // Since the controller is still storing the older view in case it'll get re-displayed
+ // later, the listener shouldn't be notified
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
}
@Test
fun displayView_viewDoesNotDisappearsBeforeTimeout() {
+ val listener = registerListener()
+
val state = getState()
underTest.displayView(state)
reset(windowManager)
@@ -210,10 +217,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
fakeClock.advanceTime(TIMEOUT_MS - 1)
verify(windowManager, never()).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
}
@Test
fun displayView_viewDisappearsAfterTimeout() {
+ val listener = registerListener()
+
val state = getState()
underTest.displayView(state)
reset(windowManager)
@@ -221,10 +231,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
fakeClock.advanceTime(TIMEOUT_MS + 1)
verify(windowManager).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
}
@Test
fun displayView_calledAgainBeforeTimeout_timeoutReset() {
+ val listener = registerListener()
+
// First, display the view
val state = getState()
underTest.displayView(state)
@@ -239,10 +252,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
// Verify we didn't hide the view
verify(windowManager, never()).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
}
@Test
fun displayView_calledAgainBeforeTimeout_eventuallyTimesOut() {
+ val listener = registerListener()
+
// First, display the view
val state = getState()
underTest.displayView(state)
@@ -255,6 +271,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
fakeClock.advanceTime(TIMEOUT_MS + 1)
verify(windowManager).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
}
@Test
@@ -271,25 +288,9 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
}
@Test
- fun viewUpdatedWithNewOnViewTimeoutRunnable_newRunnableUsed() {
- var runnable1Run = false
- underTest.displayView(ViewInfo(name = "name", id = "id1", windowTitle = "1")) {
- runnable1Run = true
- }
-
- var runnable2Run = false
- underTest.displayView(ViewInfo(name = "name", id = "id1", windowTitle = "1")) {
- runnable2Run = true
- }
-
- fakeClock.advanceTime(TIMEOUT_MS + 1)
-
- assertThat(runnable1Run).isFalse()
- assertThat(runnable2Run).isTrue()
- }
-
- @Test
fun multipleViewsWithDifferentIds_moreRecentReplacesOlder() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "name",
@@ -315,10 +316,16 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
assertThat(windowParamsCaptor.allValues[1].title).isEqualTo("Second Fake Window Title")
verify(windowManager).removeView(viewCaptor.allValues[0])
verify(configurationController, never()).removeCallback(any())
+
+ // Since the controller is still storing the older view in case it'll get re-displayed
+ // later, the listener shouldn't be notified
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
}
@Test
- fun multipleViewsWithDifferentIds_recentActiveViewIsDisplayed() {
+ fun multipleViewsWithDifferentIds_newViewRemoved_previousViewIsDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(ViewInfo("First name", id = "id1"))
verify(windowManager).addView(any(), any())
@@ -329,24 +336,35 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager).removeView(any())
verify(windowManager).addView(any(), any())
reset(windowManager)
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
+ // WHEN the current view is removed
underTest.removeView("id2", "test reason")
+ // THEN it's correctly removed
verify(windowManager).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly("id2")
+
+ // And the previous view is correctly added
verify(windowManager).addView(any(), any())
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1")
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name")
+ // WHEN the previous view times out
reset(windowManager)
fakeClock.advanceTime(TIMEOUT_MS + 1)
+ // THEN it is also removed
verify(windowManager).removeView(any())
assertThat(underTest.activeViews.size).isEqualTo(0)
verify(configurationController).removeCallback(any())
+ assertThat(listener.permanentlyRemovedIds).isEqualTo(listOf("id2", "id1"))
}
@Test
fun multipleViewsWithDifferentIds_oldViewRemoved_recentViewIsDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(ViewInfo("First name", id = "id1"))
verify(windowManager).addView(any(), any())
@@ -361,7 +379,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
// WHEN an old view is removed
underTest.removeView("id1", "test reason")
- // THEN we don't update anything
+ // THEN we don't update anything except the listener
+ assertThat(listener.permanentlyRemovedIds).containsExactly("id1")
verify(windowManager, never()).removeView(any())
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2")
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
@@ -372,10 +391,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager).removeView(any())
assertThat(underTest.activeViews.size).isEqualTo(0)
verify(configurationController).removeCallback(any())
+ assertThat(listener.permanentlyRemovedIds).isEqualTo(listOf("id1", "id2"))
}
@Test
fun multipleViewsWithDifferentIds_threeDifferentViews_recentActiveViewIsDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(ViewInfo("First name", id = "id1"))
underTest.displayView(ViewInfo("Second name", id = "id2"))
underTest.displayView(ViewInfo("Third name", id = "id3"))
@@ -387,6 +409,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
underTest.removeView("id3", "test reason")
verify(windowManager).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).isEqualTo(listOf("id3"))
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2")
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
verify(configurationController, never()).removeCallback(any())
@@ -395,6 +418,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
underTest.removeView("id2", "test reason")
verify(windowManager).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).isEqualTo(listOf("id3", "id2"))
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1")
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name")
verify(configurationController, never()).removeCallback(any())
@@ -403,6 +427,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
fakeClock.advanceTime(TIMEOUT_MS + 1)
verify(windowManager).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).isEqualTo(listOf("id3", "id2", "id1"))
assertThat(underTest.activeViews.size).isEqualTo(0)
verify(configurationController).removeCallback(any())
}
@@ -438,6 +463,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
@Test
fun multipleViews_mostRecentViewRemoved_otherViewsTimedOutAndNotDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(ViewInfo("First name", id = "id1", timeoutMs = 4000))
fakeClock.advanceTime(1000)
underTest.displayView(ViewInfo("Second name", id = "id2", timeoutMs = 4000))
@@ -451,10 +478,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager, never()).addView(any(), any())
assertThat(underTest.activeViews.size).isEqualTo(0)
verify(configurationController).removeCallback(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly("id1", "id2", "id3")
}
@Test
fun multipleViews_mostRecentViewRemoved_viewWithShortTimeLeftNotDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(ViewInfo("First name", id = "id1", timeoutMs = 4000))
fakeClock.advanceTime(1000)
underTest.displayView(ViewInfo("Second name", id = "id2", timeoutMs = 2500))
@@ -467,10 +497,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager, never()).addView(any(), any())
assertThat(underTest.activeViews.size).isEqualTo(0)
verify(configurationController).removeCallback(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly("id1", "id2")
}
@Test
fun lowerThenHigherPriority_higherReplacesLower() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "normal",
@@ -499,10 +532,15 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor))
assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title")
verify(configurationController, never()).removeCallback(any())
+ // Since the controller is still storing the older view in case it'll get re-displayed
+ // later, the listener shouldn't be notified
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
}
@Test
fun lowerThenHigherPriority_lowerPriorityRedisplayed() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "normal",
@@ -537,6 +575,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
// THEN the normal view is re-displayed
verify(windowManager).removeView(viewCaptor.allValues[1])
+ assertThat(listener.permanentlyRemovedIds).containsExactly("critical")
verify(windowManager).addView(any(), capture(windowParamsCaptor))
assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title")
verify(configurationController, never()).removeCallback(any())
@@ -544,6 +583,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
@Test
fun lowerThenHigherPriority_lowerPriorityNotRedisplayedBecauseTimedOut() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "normal",
@@ -573,6 +614,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager, never()).addView(any(), any())
assertThat(underTest.activeViews).isEmpty()
verify(configurationController).removeCallback(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly("critical", "normal")
}
@Test
@@ -609,6 +651,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
@Test
fun higherThenLowerPriority_lowerEventuallyDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "critical",
@@ -644,6 +688,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
// THEN the second normal view is displayed
verify(windowManager).removeView(viewCaptor.value)
+ assertThat(listener.permanentlyRemovedIds).containsExactly("critical")
verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor))
assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title")
assertThat(underTest.activeViews.size).isEqualTo(1)
@@ -652,6 +697,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
@Test
fun higherThenLowerPriority_lowerNotDisplayedBecauseTimedOut() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "critical",
@@ -691,10 +738,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager, never()).addView(any(), any())
assertThat(underTest.activeViews).isEmpty()
verify(configurationController).removeCallback(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly("critical", "normal")
}
@Test
fun criticalThenNewCritical_newCriticalDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "critical 1",
@@ -724,10 +774,15 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title 2")
assertThat(underTest.activeViews.size).isEqualTo(2)
verify(configurationController, never()).removeCallback(any())
+ // Since the controller is still storing the older view in case it'll get re-displayed
+ // later, the listener shouldn't be notified
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
}
@Test
fun normalThenNewNormal_newNormalDisplayed() {
+ val listener = registerListener()
+
underTest.displayView(
ViewInfo(
name = "normal 1",
@@ -757,6 +812,9 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title 2")
assertThat(underTest.activeViews.size).isEqualTo(2)
verify(configurationController, never()).removeCallback(any())
+ // Since the controller is still storing the older view in case it'll get re-displayed
+ // later, the listener shouldn't be notified
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
}
@Test
@@ -957,25 +1015,103 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
}
@Test
- fun removeView_viewRemovedAndRemovalLogged() {
+ fun removeView_viewRemovedAndRemovalLoggedAndListenerNotified() {
+ val listener = registerListener()
+
// First, add the view
underTest.displayView(getState())
// Then, remove it
val reason = "test reason"
- val deviceId = "id"
- underTest.removeView(deviceId, reason)
+ underTest.removeView(DEFAULT_ID, reason)
verify(windowManager).removeView(any())
- verify(logger).logViewRemoval(deviceId, reason)
+ verify(logger).logViewRemoval(DEFAULT_ID, reason)
verify(configurationController).removeCallback(any())
+ assertThat(listener.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
}
@Test
- fun removeView_noAdd_viewNotRemoved() {
+ fun removeView_noAdd_viewNotRemovedAndListenerNotNotified() {
+ val listener = registerListener()
+
underTest.removeView("id", "reason")
verify(windowManager, never()).removeView(any())
+ assertThat(listener.permanentlyRemovedIds).isEmpty()
+ }
+
+ @Test
+ fun listenerRegistered_notifiedOnRemoval() {
+ val listener = registerListener()
+ underTest.displayView(getState())
+
+ underTest.removeView(DEFAULT_ID, "reason")
+
+ assertThat(listener.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
+ }
+
+ @Test
+ fun listenerRegistered_notifiedOnTimedOutEvenWhenNotDisplayed() {
+ val listener = registerListener()
+ underTest.displayView(
+ ViewInfo(
+ id = "id1",
+ name = "name1",
+ timeoutMs = 3000,
+ ),
+ )
+
+ // Display a second view
+ underTest.displayView(
+ ViewInfo(
+ id = "id2",
+ name = "name2",
+ timeoutMs = 2500,
+ ),
+ )
+
+ // WHEN the second view times out
+ fakeClock.advanceTime(2501)
+
+ // THEN the listener is notified of both IDs, since id2 timed out and id1 doesn't have
+ // enough time left to be redisplayed
+ assertThat(listener.permanentlyRemovedIds).containsExactly("id1", "id2")
+ }
+
+ @Test
+ fun multipleListeners_allNotified() {
+ val listener1 = registerListener()
+ val listener2 = registerListener()
+ val listener3 = registerListener()
+
+ underTest.displayView(getState())
+
+ underTest.removeView(DEFAULT_ID, "reason")
+
+ assertThat(listener1.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
+ assertThat(listener2.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
+ assertThat(listener3.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
+ }
+
+ @Test
+ fun sameListenerRegisteredMultipleTimes_onlyNotifiedOnce() {
+ val listener = registerListener()
+ underTest.registerListener(listener)
+ underTest.registerListener(listener)
+
+ underTest.displayView(getState())
+
+ underTest.removeView(DEFAULT_ID, "reason")
+
+ assertThat(listener.permanentlyRemovedIds).hasSize(1)
+ assertThat(listener.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
+ }
+
+ private fun registerListener(): Listener {
+ return Listener().also {
+ underTest.registerListener(it)
+ }
}
private fun getState(name: String = "name") = ViewInfo(name)
@@ -1030,9 +1166,17 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
override val windowTitle: String = "Window Title",
override val wakeReason: String = "WAKE_REASON",
override val timeoutMs: Int = TIMEOUT_MS.toInt(),
- override val id: String = "id",
+ override val id: String = DEFAULT_ID,
override val priority: ViewPriority = ViewPriority.NORMAL,
) : TemporaryViewInfo()
+
+ inner class Listener : TemporaryViewDisplayController.Listener {
+ val permanentlyRemovedIds = mutableListOf<String>()
+ override fun onInfoPermanentlyRemoved(id: String) {
+ permanentlyRemovedIds.add(id)
+ }
+ }
}
private const val TIMEOUT_MS = 10000L
+private const val DEFAULT_ID = "defaultId"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
index 90178c6a0096..45eb1f9ec431 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
@@ -20,6 +20,7 @@ import android.os.PowerManager
import android.os.VibrationEffect
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
@@ -43,6 +44,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.ViewPriority
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.view.ViewUtil
@@ -54,6 +57,7 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -74,6 +78,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var viewUtil: ViewUtil
@Mock private lateinit var vibratorHelper: VibratorHelper
+ @Mock private lateinit var swipeGestureHandler: SwipeChipbarAwayGestureHandler
private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder
private lateinit var fakeWakeLock: WakeLockFake
private lateinit var fakeClock: FakeSystemClock
@@ -106,6 +111,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
powerManager,
falsingManager,
falsingCollector,
+ swipeGestureHandler,
viewUtil,
vibratorHelper,
fakeWakeLockBuilder,
@@ -430,17 +436,101 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("new title text"), any())
}
+ @Test
+ fun swipeToDismiss_false_neverListensForGesture() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+ Text.Loaded("title text"),
+ endItem = ChipbarEndItem.Loading,
+ allowSwipeToDismiss = false,
+ )
+ )
+
+ verify(swipeGestureHandler, never()).addOnGestureDetectedCallback(any(), any())
+ }
+
+ @Test
+ fun swipeToDismiss_true_listensForGesture() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+ Text.Loaded("title text"),
+ endItem = ChipbarEndItem.Loading,
+ allowSwipeToDismiss = true,
+ )
+ )
+
+ verify(swipeGestureHandler).addOnGestureDetectedCallback(any(), any())
+ }
+
+ @Test
+ fun swipeToDismiss_swipeOccurs_viewDismissed() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+ Text.Loaded("title text"),
+ endItem = ChipbarEndItem.Loading,
+ allowSwipeToDismiss = true,
+ )
+ )
+ val view = getChipbarView()
+
+ val callbackCaptor = argumentCaptor<(MotionEvent) -> Unit>()
+ verify(swipeGestureHandler).addOnGestureDetectedCallback(any(), capture(callbackCaptor))
+
+ callbackCaptor.value.invoke(MotionEvent.obtain(0L, 0L, 0, 0f, 0f, 0))
+
+ verify(windowManager).removeView(view)
+ }
+
+ @Test
+ fun swipeToDismiss_viewUpdatedToFalse_swipeOccurs_viewNotDismissed() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+ Text.Loaded("title text"),
+ endItem = ChipbarEndItem.Loading,
+ allowSwipeToDismiss = true,
+ )
+ )
+ val view = getChipbarView()
+ val callbackCaptor = argumentCaptor<(MotionEvent) -> Unit>()
+ verify(swipeGestureHandler).addOnGestureDetectedCallback(any(), capture(callbackCaptor))
+
+ // WHEN the view is updated to not allow swipe-to-dismiss
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+ Text.Loaded("title text"),
+ endItem = ChipbarEndItem.Loading,
+ allowSwipeToDismiss = false,
+ )
+ )
+
+ // THEN the callback is removed
+ verify(swipeGestureHandler).removeOnGestureDetectedCallback(any())
+
+ // And WHEN the old callback is invoked
+ callbackCaptor.value.invoke(MotionEvent.obtain(0L, 0L, 0, 0f, 0f, 0))
+
+ // THEN it is ignored and view isn't removed
+ verify(windowManager, never()).removeView(view)
+ }
+
private fun createChipbarInfo(
startIcon: Icon,
text: Text,
endItem: ChipbarEndItem?,
vibrationEffect: VibrationEffect? = null,
+ allowSwipeToDismiss: Boolean = false,
): ChipbarInfo {
return ChipbarInfo(
TintedIcon(startIcon, tintAttr = null),
text,
endItem,
vibrationEffect,
+ allowSwipeToDismiss,
windowTitle = WINDOW_TITLE,
wakeReason = WAKE_REASON,
timeoutMs = TIMEOUT,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
index 4ef4e6ca6540..ffac8f6aabe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
@@ -43,6 +43,7 @@ class FakeChipbarCoordinator(
powerManager: PowerManager,
falsingManager: FalsingManager,
falsingCollector: FalsingCollector,
+ swipeChipbarAwayGestureHandler: SwipeChipbarAwayGestureHandler,
viewUtil: ViewUtil,
vibratorHelper: VibratorHelper,
wakeLockBuilder: WakeLock.Builder,
@@ -59,6 +60,7 @@ class FakeChipbarCoordinator(
powerManager,
falsingManager,
falsingCollector,
+ swipeChipbarAwayGestureHandler,
viewUtil,
vibratorHelper,
wakeLockBuilder,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt
new file mode 100644
index 000000000000..a87a95060a7e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.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.temporarydisplay.chipbar
+
+import android.graphics.Rect
+import android.view.MotionEvent
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class SwipeChipbarAwayGestureHandlerTest : SysuiTestCase() {
+
+ private lateinit var underTest: SwipeChipbarAwayGestureHandler
+
+ @Before
+ fun setUp() {
+ underTest = SwipeChipbarAwayGestureHandler(context, mock())
+ }
+
+ @Test
+ fun startOfGestureIsWithinBounds_noViewFetcher_returnsFalse() {
+ assertThat(underTest.startOfGestureIsWithinBounds(createMotionEvent())).isFalse()
+ }
+
+ @Test
+ fun startOfGestureIsWithinBounds_usesViewFetcher_aboveBottom_returnsTrue() {
+ val view = createMockView()
+
+ underTest.setViewFetcher { view }
+
+ val motionEvent = createMotionEvent(y = VIEW_BOTTOM - 100f)
+ assertThat(underTest.startOfGestureIsWithinBounds(motionEvent)).isTrue()
+ }
+
+ @Test
+ fun startOfGestureIsWithinBounds_usesViewFetcher_slightlyBelowBottom_returnsTrue() {
+ val view = createMockView()
+
+ underTest.setViewFetcher { view }
+
+ val motionEvent = createMotionEvent(y = VIEW_BOTTOM + 20f)
+ assertThat(underTest.startOfGestureIsWithinBounds(motionEvent)).isTrue()
+ }
+
+ @Test
+ fun startOfGestureIsWithinBounds_usesViewFetcher_tooFarDown_returnsFalse() {
+ val view = createMockView()
+
+ underTest.setViewFetcher { view }
+
+ val motionEvent = createMotionEvent(y = VIEW_BOTTOM * 4f)
+ assertThat(underTest.startOfGestureIsWithinBounds(motionEvent)).isFalse()
+ }
+
+ @Test
+ fun startOfGestureIsWithinBounds_viewFetcherReset_returnsFalse() {
+ val view = createMockView()
+
+ underTest.setViewFetcher { view }
+
+ val motionEvent = createMotionEvent(y = VIEW_BOTTOM - 100f)
+ assertThat(underTest.startOfGestureIsWithinBounds(motionEvent)).isTrue()
+
+ underTest.resetViewFetcher()
+ assertThat(underTest.startOfGestureIsWithinBounds(motionEvent)).isFalse()
+ }
+
+ private fun createMotionEvent(y: Float = 0f): MotionEvent {
+ return MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0f, y, 0)
+ }
+
+ private fun createMockView(): View {
+ return mock<View>().also {
+ doAnswer { invocation ->
+ val out: Rect = invocation.getArgument(0)
+ out.set(0, 0, 0, VIEW_BOTTOM)
+ null
+ }
+ .whenever(it)
+ .getBoundsOnScreen(any())
+ }
+ }
+
+ private companion object {
+ const val VIEW_BOTTOM = 455
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 2a93ffff87a5..1710709aa851 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -172,7 +172,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
verify(mDumpManager).registerDumpable(any(), any());
verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
verify(mSecureSettings).registerContentObserverForUser(
- eq(Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES)),
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
eq(false), mSettingsObserver.capture(), eq(UserHandle.USER_ALL)
);
}
@@ -790,15 +790,15 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
reset(mResources);
when(mResources.getColor(eq(android.R.color.system_accent1_500), any()))
- .thenReturn(mThemeOverlayController.mColorScheme.getAccent1().get(6));
+ .thenReturn(mThemeOverlayController.mColorScheme.getAccent1().getS500());
when(mResources.getColor(eq(android.R.color.system_accent2_500), any()))
- .thenReturn(mThemeOverlayController.mColorScheme.getAccent2().get(6));
+ .thenReturn(mThemeOverlayController.mColorScheme.getAccent2().getS500());
when(mResources.getColor(eq(android.R.color.system_accent3_500), any()))
- .thenReturn(mThemeOverlayController.mColorScheme.getAccent3().get(6));
+ .thenReturn(mThemeOverlayController.mColorScheme.getAccent3().getS500());
when(mResources.getColor(eq(android.R.color.system_neutral1_500), any()))
- .thenReturn(mThemeOverlayController.mColorScheme.getNeutral1().get(6));
+ .thenReturn(mThemeOverlayController.mColorScheme.getNeutral1().getS500());
when(mResources.getColor(eq(android.R.color.system_neutral2_500), any()))
- .thenReturn(mThemeOverlayController.mColorScheme.getNeutral2().get(6));
+ .thenReturn(mThemeOverlayController.mColorScheme.getNeutral2().getS500());
// Defers event because we already have initial colors.
verify(mThemeOverlayApplier, never())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index 30c4f97e5503..f4226bcd71c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -175,8 +175,10 @@ class FoldAodAnimationControllerTest : SysuiTestCase() {
fold()
underTest.onScreenTurningOn({})
- underTest.onStartedWakingUp()
+ // The body of onScreenTurningOn is executed on fakeExecutor,
+ // run all pending tasks before calling the next method
fakeExecutor.runAllReady()
+ underTest.onStartedWakingUp()
verify(latencyTracker).onActionStart(any())
verify(latencyTracker).onActionCancel(any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 6bfc2f1a8b8b..7d0d57b4037a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -19,9 +19,12 @@ package com.android.systemui.util.kotlin
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -35,6 +38,10 @@ import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.yield
import org.junit.Test
import org.junit.runner.RunWith
@@ -231,6 +238,170 @@ class SampleFlowTest : SysuiTestCase() {
}
}
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ThrottleFlowTest : SysuiTestCase() {
+
+ @Test
+ fun doesNotAffectEmissions_whenDelayAtLeastEqualToPeriod() = runTest {
+ // Arrange
+ val choreographer = createChoreographer(this)
+ val output = mutableListOf<Int>()
+ val collectJob = backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(1000)
+ emit(2)
+ }.throttle(1000, choreographer.fakeClock).toList(output)
+ }
+
+ // Act
+ choreographer.advanceAndRun(0)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(999)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(1)
+
+ // Assert
+ assertThat(output).containsExactly(1, 2)
+
+ // Cleanup
+ collectJob.cancel()
+ }
+
+ @Test
+ fun delaysEmissions_withShorterThanPeriodDelay_untilPeriodElapses() = runTest {
+ // Arrange
+ val choreographer = createChoreographer(this)
+ val output = mutableListOf<Int>()
+ val collectJob = backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ }.throttle(1000, choreographer.fakeClock).toList(output)
+ }
+
+ // Act
+ choreographer.advanceAndRun(0)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(500)
+ choreographer.advanceAndRun(499)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(1)
+
+ // Assert
+ assertThat(output).containsExactly(1, 2)
+
+ // Cleanup
+ collectJob.cancel()
+ }
+
+ @Test
+ fun filtersAllButLastEmission_whenMultipleEmissionsInPeriod() = runTest {
+ // Arrange
+ val choreographer = createChoreographer(this)
+ val output = mutableListOf<Int>()
+ val collectJob = backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ delay(500)
+ emit(3)
+ }.throttle(1000, choreographer.fakeClock).toList(output)
+ }
+
+ // Act
+ choreographer.advanceAndRun(0)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(500)
+ choreographer.advanceAndRun(499)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(1)
+
+ // Assert
+ assertThat(output).containsExactly(1, 3)
+
+ // Cleanup
+ collectJob.cancel()
+ }
+
+ @Test
+ fun filtersAllButLastEmission_andDelaysIt_whenMultipleEmissionsInShorterThanPeriod() = runTest {
+ // Arrange
+ val choreographer = createChoreographer(this)
+ val output = mutableListOf<Int>()
+ val collectJob = backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ delay(250)
+ emit(3)
+ }.throttle(1000, choreographer.fakeClock).toList(output)
+ }
+
+ // Act
+ choreographer.advanceAndRun(0)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(500)
+ choreographer.advanceAndRun(250)
+ choreographer.advanceAndRun(249)
+
+ // Assert
+ assertThat(output).containsExactly(1)
+
+ // Act
+ choreographer.advanceAndRun(1)
+
+ // Assert
+ assertThat(output).containsExactly(1, 3)
+
+ // Cleanup
+ collectJob.cancel()
+ }
+
+ private fun createChoreographer(testScope: TestScope) = object {
+ val fakeClock = FakeSystemClock()
+
+ fun advanceAndRun(millis: Long) {
+ fakeClock.advanceTime(millis)
+ testScope.advanceTimeBy(millis)
+ testScope.runCurrent()
+ }
+ }
+}
+
private fun <T> assertThatFlow(flow: Flow<T>) =
object {
suspend fun emitsExactly(vararg emissions: T) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakReporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakReporterTest.java
index d0420f790038..729168ab9103 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakReporterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakReporterTest.java
@@ -22,13 +22,17 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.NotificationManager;
+import android.os.UserHandle;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import org.junit.After;
import org.junit.Before;
@@ -48,6 +52,7 @@ public class LeakReporterTest extends SysuiTestCase {
private File mLeakDir;
private File mLeakDump;
private File mLeakHprof;
+ private UserTracker mUserTracker;
private NotificationManager mNotificationManager;
@Before
@@ -56,6 +61,9 @@ public class LeakReporterTest extends SysuiTestCase {
mLeakDump = new File(mLeakDir, LeakReporter.LEAK_DUMP);
mLeakHprof = new File(mLeakDir, LeakReporter.LEAK_HPROF);
+ mUserTracker = mock(UserTracker.class);
+ when(mUserTracker.getUserHandle()).thenReturn(
+ UserHandle.of(ActivityManager.getCurrentUser()));
mNotificationManager = mock(NotificationManager.class);
mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
@@ -65,7 +73,7 @@ public class LeakReporterTest extends SysuiTestCase {
return null;
}).when(mLeakDetector).dump(any(), any());
- mLeakReporter = new LeakReporter(mContext, mLeakDetector, "test@example.com");
+ mLeakReporter = new LeakReporter(mContext, mUserTracker, mLeakDetector, "test@example.com");
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 915ea1a8cd5a..066300445a94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -48,6 +48,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
@@ -101,6 +102,8 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
@Mock
private ActivityManager mActivityManager;
@Mock
+ private UserTracker mUserTracker;
+ @Mock
private DumpManager mDumpManager;
@@ -113,6 +116,7 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
// Initial non-set value
when(mRingerModeLiveData.getValue()).thenReturn(-1);
when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
// Enable group volume adjustments
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions,
@@ -124,7 +128,7 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
mNotificationManager, mVibrator, mIAudioService, mAccessibilityManager,
mPackageManager, mWakefullnessLifcycle, mCaptioningManager, mKeyguardManager,
- mActivityManager, mDumpManager, mCallback);
+ mActivityManager, mUserTracker, mDumpManager, mCallback);
mVolumeController.setEnableDialogs(true, true);
}
@@ -233,12 +237,13 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
CaptioningManager captioningManager,
KeyguardManager keyguardManager,
ActivityManager activityManager,
+ UserTracker userTracker,
DumpManager dumpManager,
C callback) {
super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
notificationManager, optionalVibrator, iAudioService, accessibilityManager,
packageManager, wakefulnessLifecycle, captioningManager, keyguardManager,
- activityManager, dumpManager);
+ activityManager, userTracker, dumpManager);
mCallbacks = callback;
ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
new file mode 100644
index 000000000000..b52786178e71
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
@@ -0,0 +1,243 @@
+/*
+ * 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.wallet.controller
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.service.quickaccesswallet.GetWalletCardsResponse
+import android.service.quickaccesswallet.QuickAccessWalletClient
+import android.service.quickaccesswallet.WalletCard
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import java.util.ArrayList
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.isNull
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class WalletContextualSuggestionsControllerTest : SysuiTestCase() {
+
+ @Mock private lateinit var walletController: QuickAccessWalletController
+ @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var featureFlags: FeatureFlags
+ @Mock private lateinit var mockContext: Context
+ @Captor private lateinit var broadcastReceiver: ArgumentCaptor<BroadcastReceiver>
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(
+ broadcastDispatcher.broadcastFlow<List<String>?>(
+ any(),
+ isNull(),
+ any(),
+ any(),
+ any()
+ )
+ )
+ .thenCallRealMethod()
+
+ whenever(featureFlags.isEnabled(eq(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)))
+ .thenReturn(true)
+
+ whenever(CARD_1.cardId).thenReturn(ID_1)
+ whenever(CARD_2.cardId).thenReturn(ID_2)
+ whenever(CARD_3.cardId).thenReturn(ID_3)
+ }
+
+ @Test
+ fun `state - has wallet cards - received contextual cards`() = runTest {
+ setUpWalletClient(listOf(CARD_1, CARD_2))
+ val latest =
+ collectLastValue(
+ createWalletContextualSuggestionsController(backgroundScope)
+ .contextualSuggestionCards,
+ )
+
+ runCurrent()
+ verifyRegistered()
+ broadcastReceiver.value.onReceive(
+ mockContext,
+ createContextualCardsIntent(listOf(ID_1, ID_2))
+ )
+
+ assertThat(latest()).containsExactly(CARD_1, CARD_2)
+ }
+
+ @Test
+ fun `state - no wallet cards - received contextual cards`() = runTest {
+ setUpWalletClient(emptyList())
+ val latest =
+ collectLastValue(
+ createWalletContextualSuggestionsController(backgroundScope)
+ .contextualSuggestionCards,
+ )
+
+ runCurrent()
+ verifyRegistered()
+ broadcastReceiver.value.onReceive(
+ mockContext,
+ createContextualCardsIntent(listOf(ID_1, ID_2))
+ )
+
+ assertThat(latest()).isEmpty()
+ }
+
+ @Test
+ fun `state - has wallet cards - no contextual cards`() = runTest {
+ setUpWalletClient(listOf(CARD_1, CARD_2))
+ val latest =
+ collectLastValue(
+ createWalletContextualSuggestionsController(backgroundScope)
+ .contextualSuggestionCards,
+ )
+
+ runCurrent()
+ verifyRegistered()
+ broadcastReceiver.value.onReceive(mockContext, createContextualCardsIntent(emptyList()))
+
+ assertThat(latest()).isEmpty()
+ }
+
+ @Test
+ fun `state - wallet cards error`() = runTest {
+ setUpWalletClient(shouldFail = true)
+ val latest =
+ collectLastValue(
+ createWalletContextualSuggestionsController(backgroundScope)
+ .contextualSuggestionCards,
+ )
+
+ runCurrent()
+ verifyRegistered()
+ broadcastReceiver.value.onReceive(
+ mockContext,
+ createContextualCardsIntent(listOf(ID_1, ID_2))
+ )
+
+ assertThat(latest()).isEmpty()
+ }
+
+ @Test
+ fun `state - no contextual cards extra`() = runTest {
+ setUpWalletClient(listOf(CARD_1, CARD_2))
+ val latest =
+ collectLastValue(
+ createWalletContextualSuggestionsController(backgroundScope)
+ .contextualSuggestionCards,
+ )
+
+ runCurrent()
+ verifyRegistered()
+ broadcastReceiver.value.onReceive(mockContext, Intent(INTENT_NAME))
+
+ assertThat(latest()).isEmpty()
+ }
+
+ @Test
+ fun `state - has wallet cards - received contextual cards - feature disabled`() = runTest {
+ whenever(featureFlags.isEnabled(eq(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)))
+ .thenReturn(false)
+ setUpWalletClient(listOf(CARD_1, CARD_2))
+ val latest =
+ collectLastValue(
+ createWalletContextualSuggestionsController(backgroundScope)
+ .contextualSuggestionCards,
+ )
+
+ runCurrent()
+ verify(broadcastDispatcher, never()).broadcastFlow(any(), isNull(), any(), any())
+ assertThat(latest()).isNull()
+ }
+
+ private fun createWalletContextualSuggestionsController(
+ scope: CoroutineScope
+ ): WalletContextualSuggestionsController {
+ return WalletContextualSuggestionsController(
+ scope,
+ walletController,
+ broadcastDispatcher,
+ featureFlags
+ )
+ }
+
+ private fun verifyRegistered() {
+ verify(broadcastDispatcher)
+ .registerReceiver(capture(broadcastReceiver), any(), isNull(), isNull(), any(), any())
+ }
+
+ private fun createContextualCardsIntent(
+ ids: List<String> = emptyList(),
+ ): Intent {
+ val intent = Intent(INTENT_NAME)
+ intent.putStringArrayListExtra("cardIds", ArrayList(ids))
+ return intent
+ }
+
+ private fun setUpWalletClient(
+ cards: List<WalletCard> = emptyList(),
+ shouldFail: Boolean = false
+ ) {
+ whenever(walletController.queryWalletCards(any())).thenAnswer { invocation ->
+ with(
+ invocation.arguments[0] as QuickAccessWalletClient.OnWalletCardsRetrievedCallback
+ ) {
+ if (shouldFail) {
+ onWalletCardRetrievalError(mock())
+ } else {
+ onWalletCardsRetrieved(GetWalletCardsResponse(cards, 0))
+ }
+ }
+ }
+ }
+
+ companion object {
+ private const val ID_1: String = "123"
+ private val CARD_1: WalletCard = mock()
+ private const val ID_2: String = "456"
+ private val CARD_2: WalletCard = mock()
+ private const val ID_3: String = "789"
+ private val CARD_3: WalletCard = mock()
+ private val INTENT_NAME: String = "WalletSuggestionsIntent"
+ }
+}
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 0fdcb95b3eed..31cce4f3168b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -32,13 +32,13 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.hamcrest.MockitoHamcrest.intThat;
+import android.app.ActivityManager;
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Surface;
@@ -49,6 +49,7 @@ import android.view.WindowMetrics;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -81,6 +82,8 @@ public class ImageWallpaperTest extends SysuiTestCase {
private Surface mSurface;
@Mock
private Context mMockContext;
+ @Mock
+ private UserTracker mUserTracker;
@Mock
private Bitmap mWallpaperBitmap;
@@ -108,13 +111,16 @@ public class ImageWallpaperTest extends SysuiTestCase {
when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
// set up wallpaper manager
- when(mWallpaperManager.getBitmapAsUser(eq(UserHandle.USER_CURRENT), anyBoolean()))
+ when(mWallpaperManager.getBitmapAsUser(eq(ActivityManager.getCurrentUser()), anyBoolean()))
.thenReturn(mWallpaperBitmap);
when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(mWallpaperManager);
// set up surface
when(mSurfaceHolder.getSurface()).thenReturn(mSurface);
doNothing().when(mSurface).hwuiDestroy();
+
+ // set up UserTracker
+ when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
}
@Test
@@ -170,7 +176,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
}
private ImageWallpaper createImageWallpaper() {
- return new ImageWallpaper(mFakeBackgroundExecutor) {
+ return new ImageWallpaper(mFakeBackgroundExecutor, mUserTracker) {
@Override
public Engine onCreateEngine() {
return new CanvasEngine() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index dec80807ec87..68ccc301755d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -91,6 +91,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.ShadeController;
@@ -361,7 +362,8 @@ public class BubblesTest extends SysuiTestCase {
mock(Handler.class),
mock(NotifPipelineFlags.class),
mock(KeyguardNotificationVisibilityProvider.class),
- mock(UiEventLogger.class)
+ mock(UiEventLogger.class),
+ mock(UserTracker.class)
);
when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
mBubbleController = new TestableBubbleController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index e5316bc83a12..ceee0bc466d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -24,6 +24,7 @@ import android.service.dreams.IDreamManager;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
@@ -48,7 +49,8 @@ public class TestableNotificationInterruptStateProviderImpl
Handler mainHandler,
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker) {
super(contentResolver,
powerManager,
dreamManager,
@@ -61,7 +63,8 @@ public class TestableNotificationInterruptStateProviderImpl
mainHandler,
flags,
keyguardNotificationVisibilityProvider,
- uiEventLogger);
+ uiEventLogger,
+ userTracker);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index bf2235aa98a9..1bab99787de4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -132,8 +132,10 @@ public abstract class SysuiTestCase {
@After
public void SysuiTeardown() {
- InstrumentationRegistry.registerInstance(mRealInstrumentation,
- InstrumentationRegistry.getArguments());
+ if (mRealInstrumentation != null) {
+ InstrumentationRegistry.registerInstance(mRealInstrumentation,
+ InstrumentationRegistry.getArguments());
+ }
if (TestableLooper.get(this) != null) {
TestableLooper.get(this).processAllMessages();
// Must remove static reference to this test object to prevent leak (b/261039202)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
index e660e1f2d845..4b973162e42f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
@@ -23,6 +23,8 @@ import android.net.Uri;
import android.os.UserHandle;
import android.util.Pair;
+import com.android.systemui.settings.UserTracker;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -57,6 +59,11 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
}
@Override
+ public UserTracker getUserTracker() {
+ return null;
+ }
+
+ @Override
public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
ContentObserver settingsObserver, int userHandle) {
List<ContentObserver> observers;
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 3fa0ab69d67c..e6abc4c90fac 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -391,7 +391,7 @@ public class SystemActionPerformer {
private boolean takeScreenshot() {
ScreenshotHelper screenshotHelper = (mScreenshotHelperSupplier != null)
? mScreenshotHelperSupplier.get() : new ScreenshotHelper(mContext);
- screenshotHelper.takeScreenshot(WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
+ screenshotHelper.takeScreenshot(
WindowManager.ScreenshotSource.SCREENSHOT_ACCESSIBILITY_ACTIONS,
new Handler(Looper.getMainLooper()), null);
return true;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c4333d96f92e..8a429331f766 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3813,6 +3813,13 @@ class StorageManagerService extends IStorageManager.Stub
final boolean includeSharedProfile =
(flags & StorageManager.FLAG_INCLUDE_SHARED_PROFILE) != 0;
+ // When the caller is the app actually hosting external storage, we
+ // should never attempt to augment the actual storage volume state,
+ // otherwise we risk confusing it with race conditions as users go
+ // through various unlocked states
+ final boolean callerIsMediaStore = UserHandle.isSameApp(callingUid,
+ mMediaStoreAuthorityAppId);
+
// Only Apps with MANAGE_EXTERNAL_STORAGE should call the API with includeSharedProfile
if (includeSharedProfile) {
try {
@@ -3825,8 +3832,13 @@ class StorageManagerService extends IStorageManager.Stub
// Checking first entry in packagesFromUid is enough as using "sharedUserId"
// mechanism is rare and discouraged. Also, Apps that share same UID share the same
// permissions.
- if (!mStorageManagerInternal.hasExternalStorageAccess(callingUid,
- packagesFromUid[0])) {
+ // Allowing Media Provider is an exception, Media Provider process should be allowed
+ // to query users across profiles, even without MANAGE_EXTERNAL_STORAGE access.
+ // Note that ordinarily Media provider process has the above permission, but if they
+ // are revoked, Storage Volume(s) should still be returned.
+ if (!callerIsMediaStore
+ && !mStorageManagerInternal.hasExternalStorageAccess(callingUid,
+ packagesFromUid[0])) {
throw new SecurityException("Only File Manager Apps permitted");
}
} catch (RemoteException re) {
@@ -3839,13 +3851,6 @@ class StorageManagerService extends IStorageManager.Stub
// point
final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM);
- // When the caller is the app actually hosting external storage, we
- // should never attempt to augment the actual storage volume state,
- // otherwise we risk confusing it with race conditions as users go
- // through various unlocked states
- final boolean callerIsMediaStore = UserHandle.isSameApp(callingUid,
- mMediaStoreAuthorityAppId);
-
final boolean userIsDemo;
final boolean userKeyUnlocked;
final boolean storagePermission;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 8624ee031a93..bda60ff2172b 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -379,16 +379,11 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
resolvedType = key.requestResolvedType;
}
- // Apply any launch flags from the ActivityOptions. This is used only by SystemUI
- // to ensure that we can launch the pending intent with a consistent launch mode even
- // if the provided PendingIntent is immutable (ie. to force an activity to launch into
- // a new task, or to launch multiple instances if supported by the app)
+ // Apply any launch flags from the ActivityOptions. This is to ensure that the caller
+ // can specify a consistent launch mode even if the PendingIntent is immutable
final ActivityOptions opts = ActivityOptions.fromBundle(options);
if (opts != null) {
- // TODO(b/254490217): Move this check into SafeActivityOptions
- if (controller.mAtmInternal.isCallerRecents(Binder.getCallingUid())) {
- finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
- }
+ finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
}
// Extract options before clearing calling identity
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 4fd739ca5e3e..4b0ae1be9d2f 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -16,6 +16,9 @@
package com.android.server.app;
+import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER;
+import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,7 +36,6 @@ import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
import android.net.Uri;
-import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.games.CreateGameSessionRequest;
@@ -50,7 +52,6 @@ import android.text.TextUtils;
import android.util.Slog;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost.SurfacePackage;
-import android.view.WindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -59,6 +60,7 @@ import com.android.internal.infra.ServiceConnector;
import com.android.internal.infra.ServiceConnector.ServiceLifecycleCallbacks;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ScreenshotHelper;
+import com.android.internal.util.ScreenshotRequest;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
@@ -861,8 +863,6 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
Slog.w(TAG, "Could not get bitmap for id: " + taskId);
callback.complete(GameScreenshotResult.createInternalErrorResult());
} else {
- final Bundle bundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(
- bitmap);
final RunningTaskInfo runningTaskInfo =
mGameTaskInfoProvider.getRunningTaskInfo(taskId);
if (runningTaskInfo == null) {
@@ -877,11 +877,17 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
callback.complete(GameScreenshotResult.createSuccessResult());
}
};
- mScreenshotHelper.provideScreenshot(bundle, crop, Insets.NONE, taskId,
- mUserHandle.getIdentifier(), gameSessionRecord.getComponentName(),
- WindowManager.ScreenshotSource.SCREENSHOT_OTHER,
- BackgroundThread.getHandler(),
- completionConsumer);
+ ScreenshotRequest request = new ScreenshotRequest.Builder(
+ TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER)
+ .setTopComponent(gameSessionRecord.getComponentName())
+ .setTaskId(taskId)
+ .setUserId(mUserHandle.getIdentifier())
+ .setBitmap(bitmap)
+ .setBoundsOnScreen(crop)
+ .setInsets(Insets.NONE)
+ .build();
+ mScreenshotHelper.takeScreenshot(
+ request, BackgroundThread.getHandler(), completionConsumer);
}
});
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 375e51c672b5..1f7232a92277 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -159,6 +159,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
private Layout mCurrentLayout = null;
private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
private int mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
+ private int mDeviceStateToBeAppliedAfterBoot = DeviceStateManager.INVALID_DEVICE_STATE;
private boolean mBootCompleted = false;
private boolean mInteractive;
@@ -353,6 +354,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
ipw.println("mDeviceStatesOnWhichToWakeUp=" + mDeviceStatesOnWhichToWakeUp);
ipw.println("mDeviceStatesOnWhichToSleep=" + mDeviceStatesOnWhichToSleep);
ipw.println("mInteractive=" + mInteractive);
+ ipw.println("mBootCompleted=" + mBootCompleted);
+
+ ipw.println();
+ ipw.println("mDeviceState=" + mDeviceState);
+ ipw.println("mPendingDeviceState=" + mPendingDeviceState);
+ ipw.println("mDeviceStateToBeAppliedAfterBoot=" + mDeviceStateToBeAppliedAfterBoot);
final int logicalDisplayCount = mLogicalDisplays.size();
ipw.println();
@@ -370,10 +377,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
}
void setDeviceStateLocked(int state, boolean isOverrideActive) {
- Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState
- + ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted);
- mPendingDeviceState = state;
-
if (!mBootCompleted) {
// The boot animation might still be in progress, we do not want to switch states now
// as the boot animation would end up with an incorrect size.
@@ -381,14 +384,19 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState
+ " until boot is completed");
}
+ mDeviceStateToBeAppliedAfterBoot = state;
return;
}
+ Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState
+ + ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted);
// As part of a state transition, we may need to turn off some displays temporarily so that
// the transition is smooth. Plus, on some devices, only one internal displays can be
// on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be
// temporarily turned off.
resetLayoutLocked(mDeviceState, state, /* isStateChangeStarting= */ true);
+ mPendingDeviceState = state;
+ mDeviceStateToBeAppliedAfterBoot = DeviceStateManager.INVALID_DEVICE_STATE;
final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
mInteractive, mBootCompleted);
final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState,
@@ -435,8 +443,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
void onBootCompleted() {
synchronized (mSyncRoot) {
mBootCompleted = true;
- if (mPendingDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) {
- setDeviceStateLocked(mPendingDeviceState, /* isOverrideActive= */ false);
+ if (mDeviceStateToBeAppliedAfterBoot != DeviceStateManager.INVALID_DEVICE_STATE) {
+ setDeviceStateLocked(mDeviceStateToBeAppliedAfterBoot,
+ /* isOverrideActive= */ false);
}
}
}
@@ -491,7 +500,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
@VisibleForTesting
boolean shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isOverrideActive,
boolean isInteractive, boolean isBootCompleted) {
- return mDeviceStatesOnWhichToSleep.get(pendingState)
+ return currentState != DeviceStateManager.INVALID_DEVICE_STATE
+ && mDeviceStatesOnWhichToSleep.get(pendingState)
&& !mDeviceStatesOnWhichToSleep.get(currentState)
&& !isOverrideActive
&& isInteractive && isBootCompleted;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b55b6dd0eb55..b380d84c7c5c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -566,6 +566,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// What we do when the user double-taps on home
private int mDoubleTapOnHomeBehavior;
+ // Whether to lock the device after the next app transition has finished.
+ private boolean mLockAfterAppTransitionFinished;
+
// Allowed theater mode wake actions
private boolean mAllowTheaterModeWakeFromKey;
private boolean mAllowTheaterModeWakeFromPowerKey;
@@ -709,7 +712,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
handleRingerChordGesture();
break;
case MSG_SCREENSHOT_CHORD:
- handleScreenShot(msg.arg1, msg.arg2);
+ handleScreenShot(msg.arg1);
break;
}
}
@@ -1055,11 +1058,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return;
}
- // Make sure the device locks. Unfortunately, this has the side-effect of briefly revealing
- // the lock screen before the dream appears. Note that locking is a side-effect of the no
- // dream action that is executed if we early return above.
- // TODO(b/261662912): Find a better way to lock the device that doesn't result in jank.
- lockNow(null);
+ synchronized (mLock) {
+ // Lock the device after the dream transition has finished.
+ mLockAfterAppTransitionFinished = true;
+ }
dreamManagerInternal.requestDream();
}
@@ -1500,9 +1502,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|| mShortPressOnStemPrimaryBehavior != SHORT_PRESS_PRIMARY_NOTHING;
}
- private void interceptScreenshotChord(int type, int source, long pressDelay) {
+ private void interceptScreenshotChord(int source, long pressDelay) {
mHandler.removeMessages(MSG_SCREENSHOT_CHORD);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SCREENSHOT_CHORD, type, source),
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SCREENSHOT_CHORD, source),
pressDelay);
}
@@ -1572,9 +1574,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
};
- private void handleScreenShot(@WindowManager.ScreenshotType int type,
- @WindowManager.ScreenshotSource int source) {
- mDefaultDisplayPolicy.takeScreenshot(type, source);
+ private void handleScreenShot(@WindowManager.ScreenshotSource int source) {
+ mDefaultDisplayPolicy.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN, source);
}
@Override
@@ -2139,6 +2140,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
handleStartTransitionForKeyguardLw(
keyguardGoingAway, false /* keyguardOccludingStarted */,
0 /* duration */);
+
+ synchronized (mLock) {
+ mLockAfterAppTransitionFinished = false;
+ }
+ }
+
+ @Override
+ public void onAppTransitionFinishedLocked(IBinder token) {
+ synchronized (mLock) {
+ if (!mLockAfterAppTransitionFinished) {
+ return;
+ }
+ mLockAfterAppTransitionFinished = false;
+ }
+
+ lockNow(null);
}
});
@@ -2170,7 +2187,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
void execute() {
mPowerKeyHandled = true;
- interceptScreenshotChord(TAKE_SCREENSHOT_FULLSCREEN,
+ interceptScreenshotChord(
SCREENSHOT_KEY_CHORD, getScreenshotChordLongPressDelay());
}
@Override
@@ -2864,8 +2881,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
case KeyEvent.KEYCODE_S:
if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
- interceptScreenshotChord(
- TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
+ interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
return key_consumed;
}
break;
@@ -3239,8 +3255,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
case KeyEvent.KEYCODE_SYSRQ:
if (down && repeatCount == 0) {
- interceptScreenshotChord(
- TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
+ interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
}
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 1ba7e687a553..861961599ada 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4715,6 +4715,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mTaskChangeNotificationController.notifyTaskFocusChanged(prevTask.mTaskId, false);
}
mTaskChangeNotificationController.notifyTaskFocusChanged(task.mTaskId, true);
+ mTaskSupervisor.mRecentTasks.add(task);
}
applyUpdateLockStateLocked(r);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 75d84eabd146..9af1b2bd40c6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2974,7 +2974,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (density == mInitialDisplayDensity) {
density = 0;
}
- mWmService.mDisplayWindowSettings.setForcedDensity(this, density, userId);
+ mWmService.mDisplayWindowSettings.setForcedDensity(getDisplayInfo(), density, userId);
}
/** @param mode {@link #FORCE_SCALING_MODE_AUTO} or {@link #FORCE_SCALING_MODE_DISABLED}. */
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 0bb4022d9289..f8fd2b953c20 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -142,6 +142,7 @@ import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.internal.util.ScreenshotHelper;
+import com.android.internal.util.ScreenshotRequest;
import com.android.internal.util.function.TriConsumer;
import com.android.internal.view.AppearanceRegion;
import com.android.internal.widget.PointerLocationView;
@@ -2666,8 +2667,9 @@ public class DisplayPolicy {
*/
public void takeScreenshot(int screenshotType, int source) {
if (mScreenshotHelper != null) {
- mScreenshotHelper.takeScreenshot(screenshotType,
- source, mHandler, null /* completionConsumer */);
+ ScreenshotRequest request =
+ new ScreenshotRequest.Builder(screenshotType, source).build();
+ mScreenshotHelper.takeScreenshot(request, mHandler, null /* completionConsumer */);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index c1b6496338a4..d87532afa5bf 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -77,14 +77,14 @@ class DisplayWindowSettings {
mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
- void setForcedDensity(DisplayContent displayContent, int density, int userId) {
- if (displayContent.isDefaultDisplay) {
+ void setForcedDensity(DisplayInfo info, int density, int userId) {
+ if (info.displayId == Display.DEFAULT_DISPLAY) {
final String densityString = density == 0 ? "" : Integer.toString(density);
Settings.Secure.putStringForUser(mService.mContext.getContentResolver(),
Settings.Secure.DISPLAY_DENSITY_FORCED, densityString, userId);
}
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final DisplayInfo displayInfo = info;
final SettingsProvider.SettingsEntry overrideSettings =
mSettingsProvider.getOverrideSettings(displayInfo);
overrideSettings.mForcedDensity = density;
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index f916ee40d538..800fe090b457 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -197,6 +197,12 @@ final class LetterboxConfiguration {
// Whether using split screen aspect ratio as a default aspect ratio for unresizable apps.
private boolean mIsSplitScreenAspectRatioForUnresizableAppsEnabled;
+ // Whether using display aspect ratio as a default aspect ratio for all letterboxed apps.
+ // mIsSplitScreenAspectRatioForUnresizableAppsEnabled and
+ // config_letterboxDefaultMinAspectRatioForUnresizableApps take priority over this for
+ // unresizable apps
+ private boolean mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox;
+
// Whether letterboxing strategy is enabled for translucent activities. If {@value false}
// all the feature is disabled
private boolean mTranslucentLetterboxingEnabled;
@@ -288,6 +294,9 @@ final class LetterboxConfiguration {
R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
+ mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = mContext.getResources()
+ .getBoolean(R.bool
+ .config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled);
mTranslucentLetterboxingEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsEnabledForTranslucentActivities);
mIsCameraCompatTreatmentEnabled = mContext.getResources().getBoolean(
@@ -943,6 +952,13 @@ final class LetterboxConfiguration {
}
/**
+ * Whether using display aspect ratio as a default aspect ratio for all letterboxed apps.
+ */
+ boolean getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox() {
+ return mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox;
+ }
+
+ /**
* Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable
* apps.
*/
@@ -951,6 +967,14 @@ final class LetterboxConfiguration {
}
/**
+ * Overrides whether using display aspect ratio as a default aspect ratio for all letterboxed
+ * apps.
+ */
+ void setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(boolean enabled) {
+ mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = enabled;
+ }
+
+ /**
* Resets whether using split screen aspect ratio as a default aspect ratio for unresizable
* apps {@link R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled}.
*/
@@ -959,6 +983,16 @@ final class LetterboxConfiguration {
R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
}
+ /**
+ * Resets whether using display aspect ratio as a default aspect ratio for all letterboxed
+ * apps {@link R.bool.config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled}.
+ */
+ void resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox() {
+ mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = mContext.getResources()
+ .getBoolean(R.bool
+ .config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled);
+ }
+
boolean isTranslucentLetterboxingEnabled() {
return mTranslucentLetterboxingOverrideEnabled || (mTranslucentLetterboxingEnabled
&& isTranslucentLetterboxingAllowed());
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 9c43c1d62ab8..67e188fa9045 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -584,7 +584,7 @@ final class LetterboxUiController {
? getSplitScreenAspectRatio()
: mActivityRecord.shouldCreateCompatDisplayInsets()
? getDefaultMinAspectRatioForUnresizableApps()
- : mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+ : getDefaultMinAspectRatio();
}
private float getDefaultMinAspectRatioForUnresizableApps() {
@@ -593,7 +593,7 @@ final class LetterboxUiController {
return mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()
> MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
? mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()
- : mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+ : getDefaultMinAspectRatio();
}
return getSplitScreenAspectRatio();
@@ -621,6 +621,16 @@ final class LetterboxUiController {
return computeAspectRatio(bounds);
}
+ private float getDefaultMinAspectRatio() {
+ final DisplayContent displayContent = mActivityRecord.getDisplayContent();
+ if (displayContent == null
+ || !mLetterboxConfiguration
+ .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()) {
+ return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+ }
+ return computeAspectRatio(new Rect(displayContent.getBounds()));
+ }
+
Resources getResources() {
return mActivityRecord.mWmService.mContext.getResources();
}
@@ -1014,6 +1024,9 @@ final class LetterboxUiController {
+ mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps());
pw.println(prefix + " isSplitScreenAspectRatioForUnresizableAppsEnabled="
+ mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled());
+ pw.println(prefix + " isDisplayAspectRatioEnabledForFixedOrientationLetterbox="
+ + mLetterboxConfiguration
+ .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox());
}
/**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index beaac05d16a6..3aa80c4ccefb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3327,12 +3327,17 @@ class Task extends TaskFragment {
// We intend to let organizer manage task visibility but it doesn't
// have enough information until we finish shell transitions.
// In the mean time we do an easy fix here.
- final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS | CHILDREN);
+ final boolean visible = isVisible();
+ final boolean show = visible || isAnimating(TRANSITION | PARENTS | CHILDREN);
if (mSurfaceControl != null) {
if (show != mLastSurfaceShowing) {
t.setVisibility(mSurfaceControl, show);
}
}
+ // Only show the overlay if the task has other visible children
+ if (mOverlayHost != null) {
+ mOverlayHost.setVisibility(t, visible);
+ }
mLastSurfaceShowing = show;
}
diff --git a/services/core/java/com/android/server/wm/TrustedOverlayHost.java b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
index 975b21c6f02c..88c410b263ca 100644
--- a/services/core/java/com/android/server/wm/TrustedOverlayHost.java
+++ b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
@@ -80,6 +80,12 @@ class TrustedOverlayHost {
}
}
+ void setVisibility(SurfaceControl.Transaction t, boolean visible) {
+ if (mSurfaceControl != null) {
+ t.setVisibility(mSurfaceControl, visible);
+ }
+ }
+
void addOverlay(SurfaceControlViewHost.SurfacePackage p, SurfaceControl currentParent) {
requireOverlaySurfaceControl();
mOverlays.add(p);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4e32a7ca3bf4..5065014b9bee 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -167,7 +167,6 @@ import android.app.IActivityManager;
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -177,7 +176,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.TestUtilityService;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -5839,6 +5837,11 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
return displayContent.mInitialDisplayDensity;
}
+
+ DisplayInfo info = mDisplayManagerInternal.getDisplayInfo(displayId);
+ if (info != null && info.hasAccess(Binder.getCallingUid())) {
+ return info.logicalDensityDpi;
+ }
}
return -1;
}
@@ -5870,6 +5873,11 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
displayContent.setForcedDensity(density, targetUserId);
+ } else {
+ DisplayInfo info = mDisplayManagerInternal.getDisplayInfo(displayId);
+ if (info != null) {
+ mDisplayWindowSettings.setForcedDensity(info, density, userId);
+ }
}
}
} finally {
@@ -5894,6 +5902,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayContent != null) {
displayContent.setForcedDensity(displayContent.mInitialDisplayDensity,
callingUserId);
+ } else {
+ DisplayInfo info = mDisplayManagerInternal.getDisplayInfo(displayId);
+ if (info != null) {
+ mDisplayWindowSettings.setForcedDensity(info, info.logicalDensityDpi,
+ userId);
+ }
}
}
} finally {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index aef6d1d15510..a06d84c44f17 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -955,6 +955,10 @@ public class WindowManagerShellCommand extends ShellCommand {
runSetBooleanFlag(pw, mLetterboxConfiguration
::setIsSplitScreenAspectRatioForUnresizableAppsEnabled);
break;
+ case "--isDisplayAspectRatioEnabledForFixedOrientationLetterbox":
+ runSetBooleanFlag(pw, mLetterboxConfiguration
+ ::setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox);
+ break;
case "--isTranslucentLetterboxingEnabled":
runSetBooleanFlag(pw, mLetterboxConfiguration
::setTranslucentLetterboxingOverrideEnabled);
@@ -1030,6 +1034,10 @@ public class WindowManagerShellCommand extends ShellCommand {
mLetterboxConfiguration
.resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
break;
+ case "IsDisplayAspectRatioEnabledForFixedOrientationLetterbox":
+ mLetterboxConfiguration
+ .resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox();
+ break;
case "isTranslucentLetterboxingEnabled":
mLetterboxConfiguration.resetTranslucentLetterboxingEnabled();
break;
@@ -1140,6 +1148,7 @@ public class WindowManagerShellCommand extends ShellCommand {
mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
mLetterboxConfiguration.resetIsEducationEnabled();
mLetterboxConfiguration.resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
+ mLetterboxConfiguration.resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox();
mLetterboxConfiguration.resetTranslucentLetterboxingEnabled();
mLetterboxConfiguration.resetCameraCompatRefreshEnabled();
mLetterboxConfiguration.resetCameraCompatRefreshCycleThroughStopEnabled();
@@ -1187,7 +1196,9 @@ public class WindowManagerShellCommand extends ShellCommand {
pw.println("Is using split screen aspect ratio as aspect ratio for unresizable apps: "
+ mLetterboxConfiguration
.getIsSplitScreenAspectRatioForUnresizableAppsEnabled());
-
+ pw.println("Is using display aspect ratio as aspect ratio for all letterboxed apps: "
+ + mLetterboxConfiguration
+ .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox());
pw.println(" Is activity \"refresh\" in camera compatibility treatment enabled: "
+ mLetterboxConfiguration.isCameraCompatRefreshEnabled());
pw.println(" Refresh using \"stopped -> resumed\" cycle: "
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 693f3a0cf8a0..eff9e8da9a76 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -271,22 +271,22 @@ public class DataManager {
private ConversationChannel getConversationChannel(String packageName, int userId,
String shortcutId, ConversationInfo conversationInfo) {
ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
- return getConversationChannel(shortcutInfo, conversationInfo);
+ return getConversationChannel(
+ shortcutInfo, conversationInfo, packageName, userId, shortcutId);
}
@Nullable
private ConversationChannel getConversationChannel(ShortcutInfo shortcutInfo,
- ConversationInfo conversationInfo) {
+ ConversationInfo conversationInfo, String packageName, int userId, String shortcutId) {
if (conversationInfo == null || conversationInfo.isDemoted()) {
return null;
}
if (shortcutInfo == null) {
- Slog.e(TAG, " Shortcut no longer found");
+ Slog.e(TAG, "Shortcut no longer found");
+ mInjector.getBackgroundExecutor().execute(
+ () -> removeConversations(packageName, userId, Set.of(shortcutId)));
return null;
}
- String packageName = shortcutInfo.getPackage();
- String shortcutId = shortcutInfo.getId();
- int userId = shortcutInfo.getUserId();
int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
NotificationChannel parentChannel =
mNotificationManagerInternal.getNotificationChannel(packageName, uid,
@@ -1130,38 +1130,41 @@ public class DataManager {
public void onShortcutsRemoved(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
mInjector.getBackgroundExecutor().execute(() -> {
- int uid = Process.INVALID_UID;
- try {
- uid = mContext.getPackageManager().getPackageUidAsUser(
- packageName, user.getIdentifier());
- } catch (PackageManager.NameNotFoundException e) {
- Slog.e(TAG, "Package not found: " + packageName, e);
- }
- PackageData packageData = getPackage(packageName, user.getIdentifier());
- Set<String> shortcutIds = new HashSet<>();
+ HashSet<String> shortcutIds = new HashSet<>();
for (ShortcutInfo shortcutInfo : shortcuts) {
- if (packageData != null) {
- if (DEBUG) Log.d(TAG, "Deleting shortcut: " + shortcutInfo.getId());
- packageData.deleteDataForConversation(shortcutInfo.getId());
- }
shortcutIds.add(shortcutInfo.getId());
}
- if (uid != Process.INVALID_UID) {
- mNotificationManagerInternal.onConversationRemoved(
- packageName, uid, shortcutIds);
- }
+ removeConversations(packageName, user.getIdentifier(), shortcutIds);
});
}
}
+ private void removeConversations(
+ @NonNull String packageName, @NonNull int userId, @NonNull Set<String> shortcutIds) {
+ PackageData packageData = getPackage(packageName, userId);
+ if (packageData != null) {
+ for (String shortcutId : shortcutIds) {
+ if (DEBUG) Log.d(TAG, "Deleting shortcut: " + shortcutId);
+ packageData.deleteDataForConversation(shortcutId);
+ }
+ }
+ try {
+ int uid = mContext.getPackageManager().getPackageUidAsUser(
+ packageName, userId);
+ mNotificationManagerInternal.onConversationRemoved(packageName, uid, shortcutIds);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Package not found when removing conversation: " + packageName, e);
+ }
+ }
+
/** Listener for the notifications and their settings changes. */
private class NotificationListener extends NotificationListenerService {
private final int mUserId;
- // Conversation package name + shortcut ID -> Number of active notifications
+ // Conversation package name + shortcut ID -> Keys of active notifications
@GuardedBy("this")
- private final Map<Pair<String, String>, Integer> mActiveNotifCounts = new ArrayMap<>();
+ private final Map<Pair<String, String>, Set<String>> mActiveNotifKeys = new ArrayMap<>();
private NotificationListener(int userId) {
mUserId = userId;
@@ -1175,8 +1178,10 @@ public class DataManager {
String shortcutId = sbn.getNotification().getShortcutId();
PackageData packageData = getPackageIfConversationExists(sbn, conversationInfo -> {
synchronized (this) {
- mActiveNotifCounts.merge(
- Pair.create(sbn.getPackageName(), shortcutId), 1, Integer::sum);
+ Set<String> notificationKeys = mActiveNotifKeys.computeIfAbsent(
+ Pair.create(sbn.getPackageName(), shortcutId),
+ (unusedKey) -> new HashSet<>());
+ notificationKeys.add(sbn.getKey());
}
});
@@ -1215,12 +1220,12 @@ public class DataManager {
Pair<String, String> conversationKey =
Pair.create(sbn.getPackageName(), shortcutId);
synchronized (this) {
- int count = mActiveNotifCounts.getOrDefault(conversationKey, 0) - 1;
- if (count <= 0) {
- mActiveNotifCounts.remove(conversationKey);
+ Set<String> notificationKeys = mActiveNotifKeys.computeIfAbsent(
+ conversationKey, (unusedKey) -> new HashSet<>());
+ notificationKeys.remove(sbn.getKey());
+ if (notificationKeys.isEmpty()) {
+ mActiveNotifKeys.remove(conversationKey);
cleanupCachedShortcuts(mUserId, MAX_CACHED_RECENT_SHORTCUTS);
- } else {
- mActiveNotifCounts.put(conversationKey, count);
}
}
});
@@ -1286,7 +1291,7 @@ public class DataManager {
}
synchronized boolean hasActiveNotifications(String packageName, String shortcutId) {
- return mActiveNotifCounts.containsKey(Pair.create(packageName, shortcutId));
+ return mActiveNotifKeys.containsKey(Pair.create(packageName, shortcutId));
}
}
@@ -1349,9 +1354,11 @@ public class DataManager {
}
private void updateConversationStoreThenNotifyListeners(ConversationStore cs,
- ConversationInfo modifiedConv, ShortcutInfo shortcutInfo) {
+ ConversationInfo modifiedConv, @NonNull ShortcutInfo shortcutInfo) {
cs.addOrUpdate(modifiedConv);
- ConversationChannel channel = getConversationChannel(shortcutInfo, modifiedConv);
+ ConversationChannel channel = getConversationChannel(
+ shortcutInfo, modifiedConv, shortcutInfo.getPackage(), shortcutInfo.getUserId(),
+ shortcutInfo.getId());
if (channel != null) {
notifyConversationsListeners(Arrays.asList(channel));
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index e4f9eaf091e9..9b23f8b3fcab 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -1089,8 +1089,7 @@ public final class GameServiceProviderInstanceImplTest {
Consumer<Uri> consumer = invocation.getArgument(invocation.getArguments().length - 1);
consumer.accept(Uri.parse("a/b.png"));
return null;
- }).when(mMockScreenshotHelper).provideScreenshot(
- any(), any(), any(), anyInt(), anyInt(), any(), anyInt(), any(), any());
+ }).when(mMockScreenshotHelper).takeScreenshot(any(), any(), any());
mGameServiceProviderInstance.start();
startTask(taskId, GAME_A_MAIN_ACTIVITY);
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
index c15f6a9c3d66..5792ecb5f743 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
@@ -17,7 +17,6 @@
package com.android.server.accessibility;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_ACCESSIBILITY_ACTIONS;
-import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
@@ -301,9 +300,7 @@ public class SystemActionPerformerTest {
mSystemActionPerformer.performSystemAction(
AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
verify(mMockScreenshotHelper).takeScreenshot(
- eq(TAKE_SCREENSHOT_FULLSCREEN),
- eq(SCREENSHOT_ACCESSIBILITY_ACTIONS),
- any(Handler.class), any());
+ eq(SCREENSHOT_ACCESSIBILITY_ACTIONS), any(Handler.class), any());
}
// PendingIntent is a final class and cannot be mocked. So we are using this
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 6790ad9a5da1..650eef0338e6 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -591,6 +591,7 @@ public class LogicalDisplayMapperTest {
// 2) Mark the displays as STATE_OFF so that it can continue with transition
// 3) Send DISPLAY_DEVICE_EVENT_CHANGE to inform the mapper of the new display state
// 4) Dispatch handler events.
+ mLogicalDisplayMapper.onBootCompleted();
mLogicalDisplayMapper.setDeviceStateLocked(0, false);
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
mLooper.moveTimeForward(1000);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index b12e6ad563d1..a27602d65118 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -500,6 +500,7 @@ public final class DataManagerTest {
// The cached conversations are above the limit because every conversation has active
// notifications. To uncache one of them, the notifications for that conversation need to
// be dismissed.
+ String notificationKey = "";
for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
String shortcutId = TEST_SHORTCUT_ID + i;
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
@@ -507,11 +508,13 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
when(mNotification.getShortcutId()).thenReturn(shortcutId);
- sendGenericNotification();
+ notificationKey = String.format("notification-key-%d", i);
+ sendGenericNotificationWithKey(notificationKey);
}
// Post another notification for the last conversation.
- sendGenericNotification();
+ String otherNotificationKey = "other-notification-key";
+ sendGenericNotificationWithKey(otherNotificationKey);
// Removing one of the two notifications does not un-cache the shortcut.
listenerService.onNotificationRemoved(mGenericSbn, null,
@@ -520,6 +523,7 @@ public final class DataManagerTest {
anyInt(), any(), anyString(), any(), anyInt(), anyInt());
// Removing the second notification un-caches the shortcut.
+ when(mGenericSbn.getKey()).thenReturn(notificationKey);
listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CANCEL_ALL);
verify(mShortcutServiceInternal).uncacheShortcuts(
@@ -687,6 +691,63 @@ public final class DataManagerTest {
}
@Test
+ public void testGetConversation_trackActiveConversations() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNull();
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+
+ sendGenericNotification();
+ sendGenericNotification();
+ ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+ assertTrue(result.hasActiveNotifications());
+
+ // Both generic notifications have the same notification key, so a single dismiss will
+ // remove both of them.
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationRemoved(mGenericSbn, null,
+ NotificationListenerService.REASON_CANCEL);
+ ConversationChannel resultTwo = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+ assertFalse(resultTwo.hasActiveNotifications());
+ }
+
+ @Test
+ public void testGetConversation_unsyncedShortcut() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+ assertThat(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID)).isNotNull();
+
+ when(mShortcutServiceInternal.getShortcuts(
+ anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+ anyInt(), anyInt(), anyInt(), anyInt()))
+ .thenReturn(Collections.emptyList());
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNull();
+
+ // Conversation is removed from store as there is no matching shortcut in ShortcutManager
+ assertThat(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID)).isNull();
+ verify(mNotificationManagerInternal)
+ .onConversationRemoved(TEST_PKG_NAME, TEST_PKG_UID, Set.of(TEST_SHORTCUT_ID));
+ }
+
+ @Test
public void testOnNotificationChannelModified() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
@@ -1294,7 +1355,7 @@ public final class DataManagerTest {
sendGenericNotification();
- mDataManager.getRecentConversations(USER_ID_PRIMARY);
+ mDataManager.getRecentConversations(USER_ID_PRIMARY);
verify(mShortcutServiceInternal).getShortcuts(
anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
@@ -1665,6 +1726,12 @@ public final class DataManagerTest {
// "Sends" a notification to a non-customized notification channel - the notification channel
// is something generic like "messages" and the notification has a shortcut id
private void sendGenericNotification() {
+ sendGenericNotificationWithKey(GENERIC_KEY);
+ }
+
+ // "Sends" a notification to a non-customized notification channel with the specified key.
+ private void sendGenericNotificationWithKey(String key) {
+ when(mGenericSbn.getKey()).thenReturn(key);
when(mNotification.getChannelId()).thenReturn(PARENT_NOTIFICATION_CHANNEL_ID);
doAnswer(invocationOnMock -> {
NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
@@ -1680,7 +1747,7 @@ public final class DataManagerTest {
mParentNotificationChannel, null, null, true, 0, false, -1, false, null, null,
false, false, false, null, 0, false, 0);
return true;
- }).when(mRankingMap).getRanking(eq(GENERIC_KEY),
+ }).when(mRankingMap).getRanking(eq(key),
any(NotificationListenerService.Ranking.class));
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index eed32d7d815c..bb20244aee91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -249,6 +249,19 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
}
/**
+ * Ensures it updates recent tasks order when the last resumed activity changed.
+ */
+ @Test
+ public void testUpdateRecentTasksForTopResumed() {
+ spyOn(mSupervisor.mRecentTasks);
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task task = activity.getTask();
+
+ mAtm.setLastResumedActivityUncheckLocked(activity, "test");
+ verify(mSupervisor.mRecentTasks).add(eq(task));
+ }
+
+ /**
* Ensures that a trusted display can launch arbitrary activity and an untrusted display can't.
*/
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 98e68ca99720..b0639bffe694 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2064,7 +2064,8 @@ public class DisplayContentTests extends WindowTestsBase {
// Update the forced size and density in settings and the unique id to simualate a display
// remap.
dc.mWmService.mDisplayWindowSettings.setForcedSize(dc, forcedWidth, forcedHeight);
- dc.mWmService.mDisplayWindowSettings.setForcedDensity(dc, forcedDensity, 0 /* userId */);
+ dc.mWmService.mDisplayWindowSettings.setForcedDensity(displayInfo, forcedDensity,
+ 0 /* userId */);
dc.mCurrentUniqueDisplayId = mDisplayInfo.uniqueId + "-test";
// Trigger display changed.
dc.onDisplayChanged();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index c398a0a26016..fb4f2ee77521 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -236,8 +236,8 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testSetForcedDensity() {
- mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay, 600 /* density */,
- 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay.getDisplayInfo(),
+ 600 /* density */, 0 /* userId */);
mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity);
@@ -439,8 +439,9 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
public void testDisplayWindowSettingsAppliedOnDisplayReady() {
// Set forced densities for two displays in DisplayWindowSettings
final DisplayContent dc = createMockSimulatedDisplay();
- mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
- mDisplayWindowSettings.setForcedDensity(dc, 456, 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay.getDisplayInfo(), 123,
+ 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(dc.getDisplayInfo(), 456, 0 /* userId */);
// Apply settings to displays - the settings will be stored, but config will not be
// recalculated immediately.
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 995932c46201..e5ff91f1ba37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1912,6 +1912,132 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testDisplayAspectRatioForResizablePortraitApps() {
+ // Set up a display in portrait and ignoring orientation request.
+ int displayWidth = 1400;
+ int displayHeight = 1600;
+ setUpDisplaySizeWithApp(displayWidth, displayHeight);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(2f);
+
+ // Enable display aspect ratio to take precedence before
+ // fixedOrientationLetterboxAspectRatio
+ mWm.mLetterboxConfiguration
+ .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true);
+
+ // Set up resizable app in portrait
+ prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, displayWidth, getExpectedSplitSize(displayHeight));
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ // Check that the display aspect ratio is used by the app.
+ final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
+ final float delta = 0.01f;
+ assertEquals(targetMinAspectRatio, ActivityRecord
+ .computeAspectRatio(mActivity.getBounds()), delta);
+ }
+
+ @Test
+ public void testDisplayAspectRatioForResizableLandscapeApps() {
+ // Set up a display in landscape and ignoring orientation request.
+ int displayWidth = 1600;
+ int displayHeight = 1400;
+ setUpDisplaySizeWithApp(displayWidth, displayHeight);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(2f);
+
+ // Enable display aspect ratio to take precedence before
+ // fixedOrientationLetterboxAspectRatio
+ mWm.mLetterboxConfiguration
+ .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true);
+
+ // Set up resizable app in landscape
+ prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_LANDSCAPE, false /* isUnresizable */);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, getExpectedSplitSize(displayWidth), displayHeight);
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ // Check that the display aspect ratio is used by the app.
+ final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
+ final float delta = 0.01f;
+ assertEquals(targetMinAspectRatio, ActivityRecord
+ .computeAspectRatio(mActivity.getBounds()), delta);
+ }
+
+ @Test
+ public void testDisplayAspectRatioForUnresizableLandscapeApps() {
+ // Set up a display in portrait and ignoring orientation request.
+ int displayWidth = 1400;
+ int displayHeight = 1600;
+ setUpDisplaySizeWithApp(displayWidth, displayHeight);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f);
+ // Enable display aspect ratio to take precedence before
+ // fixedOrientationLetterboxAspectRatio
+ mWm.mLetterboxConfiguration
+ .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ // Check that the display aspect ratio is used by the app.
+ final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
+ final float delta = 0.01f;
+ assertEquals(targetMinAspectRatio, ActivityRecord
+ .computeAspectRatio(mActivity.getBounds()), delta);
+ }
+
+ @Test
+ public void testDisplayAspectRatioForUnresizablePortraitApps() {
+ // Set up a display in landscape and ignoring orientation request.
+ int displayWidth = 1600;
+ int displayHeight = 1400;
+ setUpDisplaySizeWithApp(displayWidth, displayHeight);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f);
+ // Enable display aspect ratio to take precedence before
+ // fixedOrientationLetterboxAspectRatio
+ mWm.mLetterboxConfiguration
+ .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ // Check that the display aspect ratio is used by the app.
+ final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
+ final float delta = 0.01f;
+ assertEquals(targetMinAspectRatio, ActivityRecord
+ .computeAspectRatio(mActivity.getBounds()), delta);
+ }
+
+ @Test
public void
testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() {
// Set up a display in landscape and ignoring orientation request.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index bf1d1fa98249..d31ae6aeb42a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -203,6 +203,7 @@ class TestDisplayContent extends DisplayContent {
}
final int displayId = SystemServicesTestRule.sNextDisplayId++;
+ mInfo.displayId = displayId;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
final TestDisplayContent newDisplay = createInternal(display);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 268aa3e5f5b4..f8b809463b2e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -253,6 +253,12 @@ class WindowTestsBase extends SystemServiceTestsBase {
// device form factors.
mAtm.mWindowManager.mLetterboxConfiguration
.setIsSplitScreenAspectRatioForUnresizableAppsEnabled(false);
+ // Ensure aspect ratio for al apps isn't overridden on any device target.
+ // {@link com.android.internal.R.bool
+ // .config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled}, may be set on
+ // some device form factors.
+ mAtm.mWindowManager.mLetterboxConfiguration
+ .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(false);
checkDeviceSpecificOverridesNotApplied();
}
@@ -267,6 +273,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
mAtm.mWindowManager.mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
mAtm.mWindowManager.mLetterboxConfiguration
.resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
+ mAtm.mWindowManager.mLetterboxConfiguration
+ .resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox();
}
/**