summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp8
-rw-r--r--Ravenwood.bp24
-rw-r--r--config/Android.bp2
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl68
-rw-r--r--core/java/android/app/ActivityTaskManager.java7
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java34
-rw-r--r--core/java/android/app/admin/PackageSetPolicyValue.java (renamed from core/java/android/app/admin/StringSetPolicyValue.java)26
-rw-r--r--core/java/android/app/admin/SystemUpdatePolicy.java5
-rw-r--r--core/java/android/app/admin/flags/flags.aconfig21
-rw-r--r--core/java/android/app/usage/flags.aconfig11
-rw-r--r--core/java/android/content/AttributionSource.java3
-rw-r--r--core/java/android/content/pm/multiuser.aconfig7
-rw-r--r--core/java/android/net/vcn/flags.aconfig20
-rw-r--r--core/java/android/os/IHintManager.aidl12
-rw-r--r--core/java/android/tracing/inputmethod/InputMethodDataSource.java58
-rw-r--r--core/java/android/view/ImeBackAnimationController.java26
-rw-r--r--core/java/android/view/InsetsController.java7
-rw-r--r--core/java/android/view/PointerIcon.java4
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/android/view/View.java9
-rw-r--r--core/java/android/view/ViewRootImpl.java72
-rw-r--r--core/java/android/view/animation/AnimationSet.java2
-rw-r--r--core/java/android/view/animation/Transformation.java1
-rw-r--r--core/java/android/view/autofill/AutofillManager.java13
-rw-r--r--core/java/android/view/autofill/IAutoFillManager.aidl2
-rw-r--r--core/java/android/view/flags/view_flags.aconfig2
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java1
-rw-r--r--core/java/android/window/TaskFragmentOrganizer.java15
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig7
-rw-r--r--core/java/android/window/flags/responsible_apis.aconfig7
-rw-r--r--core/java/android/window/flags/windowing_sdk.aconfig7
-rw-r--r--core/java/com/android/internal/content/PackageMonitor.java50
-rw-r--r--core/java/com/android/internal/inputmethod/ImeTracing.java6
-rw-r--r--core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java178
-rw-r--r--core/java/com/android/internal/jank/Cuj.java14
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java9
-rw-r--r--core/jni/android_os_HwParcel.cpp5
-rw-r--r--core/jni/android_os_HwParcel.h8
-rw-r--r--core/res/res/layout/side_fps_toast.xml18
-rw-r--r--core/res/res/values-af/strings.xml6
-rw-r--r--core/res/res/values-am/strings.xml18
-rw-r--r--core/res/res/values-ar/strings.xml6
-rw-r--r--core/res/res/values-as/strings.xml18
-rw-r--r--core/res/res/values-az/strings.xml18
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml6
-rw-r--r--core/res/res/values-be/strings.xml18
-rw-r--r--core/res/res/values-bg/strings.xml18
-rw-r--r--core/res/res/values-bn/strings.xml18
-rw-r--r--core/res/res/values-bs/strings.xml18
-rw-r--r--core/res/res/values-ca/strings.xml6
-rw-r--r--core/res/res/values-cs/strings.xml18
-rw-r--r--core/res/res/values-da/strings.xml6
-rw-r--r--core/res/res/values-de/strings.xml18
-rw-r--r--core/res/res/values-el/strings.xml18
-rw-r--r--core/res/res/values-en-rAU/strings.xml6
-rw-r--r--core/res/res/values-en-rCA/strings.xml6
-rw-r--r--core/res/res/values-en-rGB/strings.xml6
-rw-r--r--core/res/res/values-en-rIN/strings.xml6
-rw-r--r--core/res/res/values-en-rXC/strings.xml6
-rw-r--r--core/res/res/values-es-rUS/strings.xml18
-rw-r--r--core/res/res/values-es/strings.xml6
-rw-r--r--core/res/res/values-et/strings.xml6
-rw-r--r--core/res/res/values-eu/strings.xml24
-rw-r--r--core/res/res/values-fa/strings.xml20
-rw-r--r--core/res/res/values-fi/strings.xml18
-rw-r--r--core/res/res/values-fr-rCA/strings.xml20
-rw-r--r--core/res/res/values-fr/strings.xml8
-rw-r--r--core/res/res/values-gl/strings.xml6
-rw-r--r--core/res/res/values-gu/strings.xml6
-rw-r--r--core/res/res/values-hi/strings.xml18
-rw-r--r--core/res/res/values-hr/strings.xml18
-rw-r--r--core/res/res/values-hu/strings.xml6
-rw-r--r--core/res/res/values-hy/strings.xml6
-rw-r--r--core/res/res/values-in/strings.xml18
-rw-r--r--core/res/res/values-is/strings.xml6
-rw-r--r--core/res/res/values-it/strings.xml18
-rw-r--r--core/res/res/values-iw/strings.xml18
-rw-r--r--core/res/res/values-ja/strings.xml18
-rw-r--r--core/res/res/values-ka/strings.xml18
-rw-r--r--core/res/res/values-kk/strings.xml8
-rw-r--r--core/res/res/values-km/strings.xml18
-rw-r--r--core/res/res/values-kn/strings.xml18
-rw-r--r--core/res/res/values-ko/strings.xml18
-rw-r--r--core/res/res/values-ky/strings.xml6
-rw-r--r--core/res/res/values-lo/strings.xml6
-rw-r--r--core/res/res/values-lt/strings.xml6
-rw-r--r--core/res/res/values-lv/strings.xml6
-rw-r--r--core/res/res/values-mk/strings.xml18
-rw-r--r--core/res/res/values-ml/strings.xml6
-rw-r--r--core/res/res/values-mn/strings.xml6
-rw-r--r--core/res/res/values-mr/strings.xml6
-rw-r--r--core/res/res/values-ms/strings.xml18
-rw-r--r--core/res/res/values-my/strings.xml6
-rw-r--r--core/res/res/values-nb/strings.xml18
-rw-r--r--core/res/res/values-ne/strings.xml14
-rw-r--r--core/res/res/values-nl/strings.xml18
-rw-r--r--core/res/res/values-or/strings.xml18
-rw-r--r--core/res/res/values-pa/strings.xml18
-rw-r--r--core/res/res/values-pl/strings.xml18
-rw-r--r--core/res/res/values-pt-rBR/strings.xml18
-rw-r--r--core/res/res/values-pt-rPT/strings.xml18
-rw-r--r--core/res/res/values-pt/strings.xml18
-rw-r--r--core/res/res/values-ro/strings.xml6
-rw-r--r--core/res/res/values-ru/strings.xml6
-rw-r--r--core/res/res/values-si/strings.xml18
-rw-r--r--core/res/res/values-sk/strings.xml18
-rw-r--r--core/res/res/values-sl/strings.xml18
-rw-r--r--core/res/res/values-sr/strings.xml6
-rw-r--r--core/res/res/values-sv/strings.xml18
-rw-r--r--core/res/res/values-sw/strings.xml18
-rw-r--r--core/res/res/values-ta/strings.xml18
-rw-r--r--core/res/res/values-te/strings.xml18
-rw-r--r--core/res/res/values-th/strings.xml18
-rw-r--r--core/res/res/values-tl/strings.xml6
-rw-r--r--core/res/res/values-tr/strings.xml18
-rw-r--r--core/res/res/values-uk/strings.xml12
-rw-r--r--core/res/res/values-ur/strings.xml6
-rw-r--r--core/res/res/values-uz/strings.xml6
-rw-r--r--core/res/res/values-vi/strings.xml6
-rw-r--r--core/res/res/values-zh-rCN/strings.xml6
-rw-r--r--core/res/res/values-zh-rHK/strings.xml10
-rw-r--r--core/res/res/values-zu/strings.xml6
-rw-r--r--core/res/res/values/config.xml12
-rw-r--r--core/res/res/values/strings.xml19
-rw-r--r--core/res/res/values/symbols.xml13
-rw-r--r--core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java17
-rw-r--r--core/tests/coretests/src/android/view/ViewFrameRateTest.java47
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java23
-rw-r--r--core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java32
-rw-r--r--data/keyboards/Android.bp6
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java10
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java20
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java2
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java42
-rw-r--r--libs/WindowManager/Shell/aconfig/multitasking.aconfig7
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java77
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java43
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java36
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java8
-rw-r--r--libs/WindowManager/Shell/tests/OWNERS2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java20
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java51
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt13
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java43
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java16
-rw-r--r--libs/input/PointerController.cpp121
-rw-r--r--libs/input/PointerController.h20
-rw-r--r--libs/input/PointerControllerContext.h1
-rw-r--r--libs/input/SpriteController.cpp33
-rw-r--r--libs/input/SpriteController.h38
-rw-r--r--libs/input/TouchSpotController.cpp7
-rw-r--r--libs/input/TouchSpotController.h5
-rw-r--r--libs/input/tests/PointerController_test.cpp94
-rw-r--r--libs/input/tests/mocks/MockSprite.h1
-rw-r--r--media/java/android/media/MediaRouter2.java166
-rw-r--r--native/android/tests/performance_hint/PerformanceHintNativeTest.cpp4
-rw-r--r--nfc/java/android/nfc/cardemulation/CardEmulation.java6
-rw-r--r--nfc/java/android/nfc/cardemulation/PollingFrame.java11
-rw-r--r--packages/CarrierDefaultApp/res/values-fa/strings.xml2
-rw-r--r--packages/CredentialManager/res/values-fr/strings.xml4
-rw-r--r--packages/CredentialManager/res/values-hy/strings.xml6
-rw-r--r--packages/CredentialManager/res/values/strings.xml4
-rw-r--r--packages/CredentialManager/res/xml/autofill_service_configuration.xml2
-rw-r--r--packages/InputDevices/res/values-am/strings.xml3
-rw-r--r--packages/InputDevices/res/values-as/strings.xml3
-rw-r--r--packages/InputDevices/res/values-az/strings.xml3
-rw-r--r--packages/InputDevices/res/values-be/strings.xml3
-rw-r--r--packages/InputDevices/res/values-bg/strings.xml3
-rw-r--r--packages/InputDevices/res/values-bn/strings.xml3
-rw-r--r--packages/InputDevices/res/values-cs/strings.xml3
-rw-r--r--packages/InputDevices/res/values-de/strings.xml3
-rw-r--r--packages/InputDevices/res/values-es-rUS/strings.xml3
-rw-r--r--packages/InputDevices/res/values-fa/strings.xml3
-rw-r--r--packages/InputDevices/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/InputDevices/res/values-hi/strings.xml3
-rw-r--r--packages/InputDevices/res/values-hr/strings.xml3
-rw-r--r--packages/InputDevices/res/values-it/strings.xml3
-rw-r--r--packages/InputDevices/res/values-iw/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ja/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ka/strings.xml3
-rw-r--r--packages/InputDevices/res/values-km/strings.xml3
-rw-r--r--packages/InputDevices/res/values-kn/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ko/strings.xml3
-rw-r--r--packages/InputDevices/res/values-mk/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ms/strings.xml3
-rw-r--r--packages/InputDevices/res/values-nl/strings.xml3
-rw-r--r--packages/InputDevices/res/values-or/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pt/strings.xml3
-rw-r--r--packages/InputDevices/res/values-si/strings.xml3
-rw-r--r--packages/InputDevices/res/values-sv/strings.xml3
-rw-r--r--packages/InputDevices/res/values-sw/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ta/strings.xml3
-rw-r--r--packages/InputDevices/res/values-te/strings.xml3
-rw-r--r--packages/InputDevices/res/values-th/strings.xml3
-rw-r--r--packages/InputDevices/res/values-tr/strings.xml3
-rw-r--r--packages/InputDevices/res/values-uk/strings.xml3
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java59
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java23
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java4
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java1
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java24
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt51
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt30
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-fi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml6
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java75
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java24
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java1
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java27
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/OWNERS7
-rw-r--r--packages/SystemUI/TEST_MAPPING5
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml4
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml2
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml4
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml6
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig22
-rw-r--r--packages/SystemUI/checks/Android.bp3
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/SingletonAndroidComponentDetector.kt160
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt1
-rw-r--r--packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt3
-rw-r--r--packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SingletonAndroidComponentDetectorTest.kt182
-rw-r--r--packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt29
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt20
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt37
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeSessionModule.kt43
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt5
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt71
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt44
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/session/ui/composable/Session.kt270
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt22
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt11
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt17
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt19
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt19
-rw-r--r--packages/SystemUI/compose/scene/OWNERS3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt92
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt19
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt29
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt85
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt11
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt6
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt66
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt6
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt4
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt3
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt69
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt112
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt210
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt5
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt59
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt74
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt254
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt3
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt130
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt44
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryImplTest.kt138
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt37
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt40
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt42
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt40
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt)3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileDataInteractorTest.kt71
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileUserActionInteractorTest.kt100
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt111
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt124
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt65
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt249
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt)160
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt)0
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt20
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt1
-rw-r--r--packages/SystemUI/res-keyguard/values-ar/strings.xml12
-rw-r--r--packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-gl/strings.xml4
-rw-r--r--packages/SystemUI/res-keyguard/values-hi/strings.xml4
-rw-r--r--packages/SystemUI/res-keyguard/values-ne/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-nl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml4
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml1
-rw-r--r--packages/SystemUI/res/drawable/shelf_action_chip_divider.xml2
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay2.xml191
-rw-r--r--packages/SystemUI/res/values-af/strings.xml17
-rw-r--r--packages/SystemUI/res/values-am/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml14
-rw-r--r--packages/SystemUI/res/values-as/strings.xml7
-rw-r--r--packages/SystemUI/res/values-az/strings.xml17
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-be/strings.xml7
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml17
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml14
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml14
-rw-r--r--packages/SystemUI/res/values-da/strings.xml19
-rw-r--r--packages/SystemUI/res/values-de/strings.xml14
-rw-r--r--packages/SystemUI/res/values-el/strings.xml14
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml14
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml14
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml14
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml16
-rw-r--r--packages/SystemUI/res/values-es/strings.xml4
-rw-r--r--packages/SystemUI/res/values-et/strings.xml14
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml18
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml16
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml16
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml14
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml21
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml16
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml17
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml16
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml18
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml14
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml14
-rw-r--r--packages/SystemUI/res/values-in/strings.xml14
-rw-r--r--packages/SystemUI/res/values-is/strings.xml4
-rw-r--r--packages/SystemUI/res/values-it/strings.xml14
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml17
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml14
-rw-r--r--packages/SystemUI/res/values-km/strings.xml14
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml17
-rw-r--r--packages/SystemUI/res/values-land/styles.xml6
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml17
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml17
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml14
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml17
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml19
-rw-r--r--packages/SystemUI/res/values-my/strings.xml19
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml9
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml17
-rw-r--r--packages/SystemUI/res/values-or/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml16
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml18
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml17
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml16
-rw-r--r--packages/SystemUI/res/values-si/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml16
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/styles.xml6
-rw-r--r--packages/SystemUI/res/values-sw600dp-port/styles.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp-land/styles.xml6
-rw-r--r--packages/SystemUI/res/values-sw720dp-port/styles.xml2
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml14
-rw-r--r--packages/SystemUI/res/values-te/strings.xml18
-rw-r--r--packages/SystemUI/res/values-th/strings.xml17
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml17
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml18
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml14
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml17
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml14
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml14
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml14
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml14
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml7
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/res/values/styles.xml14
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepository.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java116
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperRepository.kt86
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperInteractor.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutHelperState.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarter.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt (renamed from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperActivity.kt)31
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt81
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModel.kt (renamed from packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModel.kt)3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileDataInteractor.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/model/OneHandedModeTileModel.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/TransitioningIconDrawable.kt134
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt102
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/slice/SliceViewManagerExt.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt111
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt121
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt60
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarterTest.kt132
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt130
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt17
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeOneHandedModeRepository.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/FakeShortcutHelperStartActivity.kt28
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt60
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt56
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt56
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractorKosmos.kt34
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/onehanded/OneHandedModeTileKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/session/shared/SessionStorageKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt60
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt6
-rw-r--r--ravenwood/Android.bp32
-rwxr-xr-xravenwood/scripts/ravenwood-stats-collector.sh10
-rw-r--r--ravenwood/texts/ravenwood-framework-policies.txt (renamed from ravenwood/texts/framework-minus-apex-ravenwood-policies.txt)0
-rw-r--r--ravenwood/texts/ravenwood-services-policies.txt (renamed from ravenwood/texts/services.core-ravenwood-policies.txt)0
-rw-r--r--services/accessibility/accessibility.aconfig10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java63
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java27
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java49
-rw-r--r--services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java11
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java6
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java52
-rw-r--r--services/autofill/java/com/android/server/autofill/SaveEventLogger.java44
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java24
-rw-r--r--services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java25
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java7
-rw-r--r--services/core/java/com/android/server/am/AppStartInfoTracker.java76
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java4
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java4
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java9
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java4
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java93
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java144
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java6
-rw-r--r--services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java3
-rw-r--r--services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java15
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java11
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java70
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubService.java207
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java41
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java18
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java53
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java14
-rw-r--r--services/core/java/com/android/server/notification/flags.aconfig7
-rw-r--r--services/core/java/com/android/server/os/BugreportManagerServiceImpl.java50
-rw-r--r--services/core/java/com/android/server/os/core_os_flags.aconfig10
-rw-r--r--services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java27
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java18
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java16
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java14
-rw-r--r--services/core/java/com/android/server/pm/VerifyingSession.java12
-rw-r--r--services/core/java/com/android/server/power/batterysaver/flags.aconfig2
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java186
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java23
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java21
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java156
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java4
-rw-r--r--services/core/java/com/android/server/wm/LetterboxConfiguration.java30
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java69
-rw-r--r--services/core/java/com/android/server/wm/OWNERS1
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java26
-rw-r--r--services/core/java/com/android/server/wm/Task.java113
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java18
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/core/jni/com_android_server_hint_HintManagerService.cpp28
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp161
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java28
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java32
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PackageSetPolicySerializer.java (renamed from services/devicepolicy/java/com/android/server/devicepolicy/StringSetPolicySerializer.java)12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PackageSetUnion.java (renamed from services/devicepolicy/java/com/android/server/devicepolicy/StringSetUnion.java)13
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java8
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java4
-rw-r--r--services/java/com/android/server/SystemServer.java38
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java43
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/autofill/SaveEventLoggerTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java132
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java153
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java35
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java124
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java55
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java95
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java33
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java10
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java7
-rw-r--r--services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java18
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java4
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java13
-rw-r--r--tests/UsbManagerTests/Android.bp3
-rw-r--r--tests/UsbManagerTests/src/com/android/server/usbtest/UsbProfileGroupSettingsManagerTest.java165
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java37
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java53
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java1
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp10
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt26
-rw-r--r--wifi/wifi.aconfig8
732 files changed, 12186 insertions, 4448 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index ab5d503eac62..0ccdf37f0c2c 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -1043,12 +1043,20 @@ aconfig_declarations {
name: "device_policy_aconfig_flags",
package: "android.app.admin.flags",
container: "system",
+ exportable: true,
srcs: [
"core/java/android/app/admin/flags/flags.aconfig",
],
}
java_aconfig_library {
+ name: "device_policy_exported_aconfig_flags_lib",
+ aconfig_declarations: "device_policy_aconfig_flags",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ mode: "exported",
+}
+
+java_aconfig_library {
name: "device_policy_aconfig_flags_lib",
aconfig_declarations: "device_policy_aconfig_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 3ab0934e9acc..255ec924abee 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -30,7 +30,7 @@ java_genrule {
name: "framework-minus-apex.ravenwood-base",
tools: ["hoststubgen"],
cmd: "$(location hoststubgen) " +
- "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
+ "@$(location :ravenwood-standard-options) " +
"--debug-log $(location hoststubgen_framework-minus-apex.log) " +
"--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
@@ -42,13 +42,13 @@ java_genrule {
"--gen-input-dump-file $(location hoststubgen_dump.txt) " +
"--in-jar $(location :framework-minus-apex-for-hoststubgen) " +
- "--policy-override-file $(location ravenwood/texts/framework-minus-apex-ravenwood-policies.txt) " +
- "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
+ "--policy-override-file $(location :ravenwood-framework-policies) " +
+ "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) ",
srcs: [
":framework-minus-apex-for-hoststubgen",
- "ravenwood/texts/framework-minus-apex-ravenwood-policies.txt",
- "ravenwood/texts/ravenwood-standard-options.txt",
- "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
+ ":ravenwood-framework-policies",
+ ":ravenwood-standard-options",
+ ":ravenwood-annotation-allowed-classes",
],
out: [
"ravenwood.jar",
@@ -118,7 +118,7 @@ java_genrule {
name: "services.core.ravenwood-base",
tools: ["hoststubgen"],
cmd: "$(location hoststubgen) " +
- "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
+ "@$(location :ravenwood-standard-options) " +
"--debug-log $(location hoststubgen_services.core.log) " +
"--stats-file $(location hoststubgen_services.core_stats.csv) " +
@@ -130,13 +130,13 @@ java_genrule {
"--gen-input-dump-file $(location hoststubgen_dump.txt) " +
"--in-jar $(location :services.core-for-hoststubgen) " +
- "--policy-override-file $(location ravenwood/texts/services.core-ravenwood-policies.txt) " +
- "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
+ "--policy-override-file $(location :ravenwood-services-policies) " +
+ "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) ",
srcs: [
":services.core-for-hoststubgen",
- "ravenwood/texts/services.core-ravenwood-policies.txt",
- "ravenwood/texts/ravenwood-standard-options.txt",
- "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
+ ":ravenwood-services-policies",
+ ":ravenwood-standard-options",
+ ":ravenwood-annotation-allowed-classes",
],
out: [
"ravenwood.jar",
diff --git a/config/Android.bp b/config/Android.bp
index adce203e1140..c9948c31f1c3 100644
--- a/config/Android.bp
+++ b/config/Android.bp
@@ -33,7 +33,7 @@ prebuilt_etc {
name: "preloaded-classes",
src: "preloaded-classes",
filename: "preloaded-classes",
- installable: false,
+ no_full_install: true,
}
filegroup {
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index dc5c7f694c58..713d8e5dd12f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -43,131 +43,189 @@ import android.window.ScreenCapture;
*/
interface IAccessibilityServiceConnection {
+ @RequiresNoPermission
void setServiceInfo(in AccessibilityServiceInfo info);
+ @RequiresNoPermission
void setAttributionTag(in String attributionTag);
+ @RequiresNoPermission
String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
in Bundle arguments);
+ @RequiresNoPermission
String[] findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
long threadId);
+ @RequiresNoPermission
String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
long accessibilityNodeId, String viewId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long threadId);
+ @RequiresNoPermission
String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
+ @RequiresNoPermission
String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
+ @RequiresNoPermission
boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
int action, in Bundle arguments, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long threadId);
+ @RequiresNoPermission
AccessibilityWindowInfo getWindow(int windowId);
+ @RequiresNoPermission
AccessibilityWindowInfo.WindowListSparseArray getWindows();
+ @RequiresNoPermission
AccessibilityServiceInfo getServiceInfo();
+ @RequiresNoPermission
boolean performGlobalAction(int action);
+
+ @RequiresNoPermission
List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions();
+ @RequiresNoPermission
void disableSelf();
+ @RequiresNoPermission
oneway void setOnKeyEventResult(boolean handled, int sequence);
+ @RequiresNoPermission
MagnificationConfig getMagnificationConfig(int displayId);
+ @RequiresNoPermission
float getMagnificationScale(int displayId);
+ @RequiresNoPermission
float getMagnificationCenterX(int displayId);
+ @RequiresNoPermission
float getMagnificationCenterY(int displayId);
+ @RequiresNoPermission
Region getMagnificationRegion(int displayId);
+ @RequiresNoPermission
Region getCurrentMagnificationRegion(int displayId);
+ @RequiresNoPermission
boolean resetMagnification(int displayId, boolean animate);
+ @RequiresNoPermission
boolean resetCurrentMagnification(int displayId, boolean animate);
+ @RequiresNoPermission
boolean setMagnificationConfig(int displayId, in MagnificationConfig config, boolean animate);
+ @RequiresNoPermission
void setMagnificationCallbackEnabled(int displayId, boolean enabled);
+ @RequiresNoPermission
boolean setSoftKeyboardShowMode(int showMode);
+ @RequiresNoPermission
int getSoftKeyboardShowMode();
+ @RequiresNoPermission
void setSoftKeyboardCallbackEnabled(boolean enabled);
- boolean switchToInputMethod(String imeId);
+ @RequiresNoPermission
+ boolean switchToInputMethod(String imeId);
- int setInputMethodEnabled(String imeId, boolean enabled);
+ @RequiresNoPermission
+ int setInputMethodEnabled(String imeId, boolean enabled);
+ @RequiresNoPermission
boolean isAccessibilityButtonAvailable();
+ @RequiresNoPermission
void sendGesture(int sequence, in ParceledListSlice gestureSteps);
+ @RequiresNoPermission
void dispatchGesture(int sequence, in ParceledListSlice gestureSteps, int displayId);
+ @RequiresNoPermission
boolean isFingerprintGestureDetectionAvailable();
+ @RequiresNoPermission
IBinder getOverlayWindowToken(int displayid);
+ @RequiresNoPermission
int getWindowIdForLeashToken(IBinder token);
+ @RequiresNoPermission
void takeScreenshot(int displayId, in RemoteCallback callback);
+ @RequiresNoPermission
void takeScreenshotOfWindow(int accessibilityWindowId, int interactionId,
in ScreenCapture.ScreenCaptureListener listener,
IAccessibilityInteractionConnectionCallback callback);
+ @RequiresNoPermission
void setGestureDetectionPassthroughRegion(int displayId, in Region region);
+ @RequiresNoPermission
void setTouchExplorationPassthroughRegion(int displayId, in Region region);
+ @RequiresNoPermission
void setFocusAppearance(int strokeWidth, int color);
+ @RequiresNoPermission
void setCacheEnabled(boolean enabled);
+ @RequiresNoPermission
oneway void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
int processId, long threadId, int callingUid, in Bundle serializedCallingStackInBundle);
+ @RequiresNoPermission
void setServiceDetectsGesturesEnabled(int displayId, boolean mode);
+ @RequiresNoPermission
void requestTouchExploration(int displayId);
+ @RequiresNoPermission
void requestDragging(int displayId, int pointerId);
+ @RequiresNoPermission
void requestDelegating(int displayId);
+ @RequiresNoPermission
void onDoubleTap(int displayId);
+ @RequiresNoPermission
void onDoubleTapAndHold(int displayId);
+ @RequiresNoPermission
void setAnimationScale(float scale);
+ @RequiresNoPermission
void setInstalledAndEnabledServices(in List<AccessibilityServiceInfo> infos);
- List<AccessibilityServiceInfo> getInstalledAndEnabledServices();
+ @RequiresNoPermission
+ List<AccessibilityServiceInfo> getInstalledAndEnabledServices();
+
+ @RequiresNoPermission
void attachAccessibilityOverlayToDisplay(int interactionId, int displayId, in SurfaceControl sc, IAccessibilityInteractionConnectionCallback callback);
+ @RequiresNoPermission
void attachAccessibilityOverlayToWindow(int interactionId, int accessibilityWindowId, in SurfaceControl sc, IAccessibilityInteractionConnectionCallback callback);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
+ @EnforcePermission("BLUETOOTH_CONNECT")
void connectBluetoothBrailleDisplay(in String bluetoothAddress, in IBrailleDisplayController controller);
+
+ @RequiresNoPermission
void connectUsbBrailleDisplay(in UsbDevice usbDevice, in IBrailleDisplayController controller);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
+ @EnforcePermission("MANAGE_ACCESSIBILITY")
void setTestBrailleDisplayData(in List<Bundle> brailleDisplays);
} \ No newline at end of file
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index be8f48df4aa6..c8ab260c8c4e 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -90,13 +90,6 @@ public class ActivityTaskManager {
public static final int RESIZE_MODE_USER = RESIZE_MODE_PRESERVE_WINDOW;
/**
- * Input parameter to {@link IActivityTaskManager#resizeTask} used by window
- * manager during a screen rotation.
- * @hide
- */
- public static final int RESIZE_MODE_SYSTEM_SCREEN_ROTATION = RESIZE_MODE_PRESERVE_WINDOW;
-
- /**
* Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
* that the resize should be performed even if the bounds appears unchanged.
* @hide
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c3bac710f9be..3c402cae98c1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6593,12 +6593,7 @@ public class Notification implements Parcelable
* @hide
*/
public RemoteViews createCompactHeadsUpContentView() {
- // TODO(b/336225281): re-evaluate custom view usage.
- if (useExistingRemoteView(mN.headsUpContentView)) {
- return fullyCustomViewRequiresDecoration(false /* fromStyle */)
- ? minimallyDecoratedHeadsUpContentView(mN.headsUpContentView)
- : mN.headsUpContentView;
- } else if (mStyle != null) {
+ if (mStyle != null) {
final RemoteViews styleView = mStyle.makeCompactHeadsUpContentView();
if (styleView != null) {
return styleView;
@@ -6611,7 +6606,7 @@ public class Notification implements Parcelable
// Notification text is shown as secondary header text
// for the minimal hun when it is provided.
// Time(when and chronometer) is not shown for the minimal hun.
- p.headerTextSecondary(p.mText).text(null).hideTime(true);
+ p.headerTextSecondary(p.mText).text(null).hideTime(true).summaryText("");
return applyStandardTemplate(
getCompactHeadsUpBaseLayoutResource(), p,
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 9ef8b38666c6..46c9e781bed1 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -21,6 +21,7 @@ import static android.app.admin.flags.Flags.FLAG_HEADLESS_DEVICE_OWNER_SINGLE_US
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.app.admin.flags.Flags;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -176,6 +177,10 @@ public final class DeviceAdminInfo implements Parcelable {
* provisioned into "affiliated" mode when on a Headless System User Mode device.
*
* <p>This mode adds a Profile Owner to all users other than the user the Device Owner is on.
+ *
+ * <p>Starting from Android version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM},
+ * DPCs should set the value of attribute "headless-device-owner-mode" inside the
+ * "headless-system-user" tag as "affiliated".
*/
public static final int HEADLESS_DEVICE_OWNER_MODE_AFFILIATED = 1;
@@ -185,6 +190,10 @@ public final class DeviceAdminInfo implements Parcelable {
*
* <p>This mode only allows a single secondary user on the device blocking the creation of
* additional secondary users.
+ *
+ * <p>Starting from Android version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM},
+ * DPCs should set the value of attribute "headless-device-owner-mode" inside the
+ * "headless-system-user" tag as "single_user".
*/
@FlaggedApi(FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED)
public static final int HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER = 2;
@@ -383,17 +392,30 @@ public final class DeviceAdminInfo implements Parcelable {
}
mSupportsTransferOwnership = true;
} else if (tagName.equals("headless-system-user")) {
- String deviceOwnerModeStringValue =
- parser.getAttributeValue(null, "device-owner-mode");
+ String deviceOwnerModeStringValue = null;
+ if (Flags.headlessSingleUserCompatibilityFix()) {
+ deviceOwnerModeStringValue = parser.getAttributeValue(
+ null, "headless-device-owner-mode");
+ }
+ if (deviceOwnerModeStringValue == null) {
+ deviceOwnerModeStringValue =
+ parser.getAttributeValue(null, "device-owner-mode");
+ }
- if (deviceOwnerModeStringValue.equalsIgnoreCase("unsupported")) {
+ if ("unsupported".equalsIgnoreCase(deviceOwnerModeStringValue)) {
mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
- } else if (deviceOwnerModeStringValue.equalsIgnoreCase("affiliated")) {
+ } else if ("affiliated".equalsIgnoreCase(deviceOwnerModeStringValue)) {
mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
- } else if (deviceOwnerModeStringValue.equalsIgnoreCase("single_user")) {
+ } else if ("single_user".equalsIgnoreCase(deviceOwnerModeStringValue)) {
mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
} else {
- throw new XmlPullParserException("headless-system-user mode must be valid");
+ if (Flags.headlessSingleUserCompatibilityFix()) {
+ Log.e(TAG, "Unknown headless-system-user mode: "
+ + deviceOwnerModeStringValue);
+ } else {
+ throw new XmlPullParserException(
+ "headless-system-user mode must be valid");
+ }
}
}
}
diff --git a/core/java/android/app/admin/StringSetPolicyValue.java b/core/java/android/app/admin/PackageSetPolicyValue.java
index 12b11f4ba687..8b253a23a299 100644
--- a/core/java/android/app/admin/StringSetPolicyValue.java
+++ b/core/java/android/app/admin/PackageSetPolicyValue.java
@@ -28,18 +28,18 @@ import java.util.Set;
/**
* @hide
*/
-public final class StringSetPolicyValue extends PolicyValue<Set<String>> {
+public final class PackageSetPolicyValue extends PolicyValue<Set<String>> {
- public StringSetPolicyValue(@NonNull Set<String> value) {
+ public PackageSetPolicyValue(@NonNull Set<String> value) {
super(value);
if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- for (String str : value) {
- PolicySizeVerifier.enforceMaxStringLength(str, "policyValue");
+ for (String packageName : value) {
+ PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
}
}
}
- public StringSetPolicyValue(Parcel source) {
+ public PackageSetPolicyValue(Parcel source) {
this(readValues(source));
}
@@ -56,7 +56,7 @@ public final class StringSetPolicyValue extends PolicyValue<Set<String>> {
public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- StringSetPolicyValue other = (StringSetPolicyValue) o;
+ PackageSetPolicyValue other = (PackageSetPolicyValue) o;
return Objects.equals(getValue(), other.getValue());
}
@@ -67,7 +67,7 @@ public final class StringSetPolicyValue extends PolicyValue<Set<String>> {
@Override
public String toString() {
- return "StringSetPolicyValue { " + getValue() + " }";
+ return "PackageNameSetPolicyValue { " + getValue() + " }";
}
@Override
@@ -84,16 +84,16 @@ public final class StringSetPolicyValue extends PolicyValue<Set<String>> {
}
@NonNull
- public static final Creator<StringSetPolicyValue> CREATOR =
- new Creator<StringSetPolicyValue>() {
+ public static final Creator<PackageSetPolicyValue> CREATOR =
+ new Creator<PackageSetPolicyValue>() {
@Override
- public StringSetPolicyValue createFromParcel(Parcel source) {
- return new StringSetPolicyValue(source);
+ public PackageSetPolicyValue createFromParcel(Parcel source) {
+ return new PackageSetPolicyValue(source);
}
@Override
- public StringSetPolicyValue[] newArray(int size) {
- return new StringSetPolicyValue[size];
+ public PackageSetPolicyValue[] newArray(int size) {
+ return new PackageSetPolicyValue[size];
}
};
}
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 7320cea16451..dede5b5f48f3 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -78,6 +78,11 @@ import java.util.stream.Collectors;
*
* <h3>Developer guide</h3>
* To learn more, read <a href="{@docRoot}work/dpc/system-updates">Manage system updates</a>.
+ * <p><strong>Note:</strong> <a href="https://source.android.com/docs/core/ota/modular-system">
+ * Google Play system updates</a> (also called Mainline updates) are automatically downloaded
+ * but require a device reboot to be installed. Refer to the mainline section in
+ * <a href="{@docRoot}work/dpc/system-updates#mainline">Manage system
+ * updates</a> for further details.</p>
*
* @see DevicePolicyManager#setSystemUpdatePolicy
* @see DevicePolicyManager#getSystemUpdatePolicy
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 18914e120d52..83daa4524696 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -303,3 +303,24 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "headless_single_user_compatibility_fix"
+ namespace: "enterprise"
+ description: "Fix for compatibility issue introduced from using single_user mode on pre-Android V builds"
+ bug: "338050276"
+ is_exported: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "headless_single_min_target_sdk"
+ namespace: "enterprise"
+ description: "Only allow DPCs targeting Android V to provision into single user mode"
+ bug: "338588825"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/app/usage/flags.aconfig b/core/java/android/app/usage/flags.aconfig
index c7b168aaf81d..04c36867271c 100644
--- a/core/java/android/app/usage/flags.aconfig
+++ b/core/java/android/app/usage/flags.aconfig
@@ -47,3 +47,14 @@ flag {
description: "Feature flag for collecting app data size by file type API"
bug: "294088945"
}
+
+flag {
+ name: "disable_idle_check"
+ namespace: "backstage_power"
+ description: "disable idle check for USER_SYSTEM during boot up"
+ is_fixed_read_only: true
+ bug: "337864590"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index af1301140358..b070742178e6 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -753,6 +753,9 @@ public final class AttributionSource implements Parcelable {
@FlaggedApi(Flags.FLAG_SET_NEXT_ATTRIBUTION_SOURCE)
public @NonNull Builder setNextAttributionSource(@NonNull AttributionSource value) {
checkNotUsed();
+ if (value == null) {
+ throw new IllegalArgumentException("Null AttributionSource not permitted.");
+ }
mBuilderFieldsSet |= 0x20;
mAttributionSourceState.next =
new AttributionSourceState[]{value.mAttributionSourceState};
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index cd1913bb26d9..83742eb7ae84 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -240,3 +240,10 @@ flag {
description: "Add entrypoint in Settings Reset options for deleting private space when lock is forgotten"
bug: "329601751"
}
+
+flag {
+ name: "allow_main_user_to_access_blocked_number_provider"
+ namespace: "multiuser"
+ description: "Allow MAIN user to access blocked number provider"
+ bug: "338579331"
+}
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index fea2c253e743..d4d1ed22dd4e 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -38,6 +38,16 @@ flag{
}
flag{
+ name: "enforce_main_user"
+ namespace: "vcn"
+ description: "Enforce main user to make VCN HSUM compatible"
+ bug: "310310661"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag{
name: "handle_seq_num_leap"
namespace: "vcn"
description: "Do not report bad network when there is a suspected sequence number leap"
@@ -45,4 +55,14 @@ flag{
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag{
+ name: "allow_disable_ipsec_loss_detector"
+ namespace: "vcn"
+ description: "Allow disabling IPsec packet loss detector"
+ bug: "336638836"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
} \ No newline at end of file
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index e057a8536fab..360b2ac4f3ca 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -18,6 +18,7 @@
package android.os;
import android.os.IHintSession;
+import android.hardware.power.ChannelConfig;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
@@ -27,6 +28,9 @@ interface IHintManager {
* Creates a {@link Session} for the given set of threads and associates to a binder token.
* Returns a config if creation is not supported, and HMS had to use the
* legacy creation method.
+ *
+ * Throws UnsupportedOperationException if ADPF is not supported, and IllegalStateException
+ * if creation is supported but fails.
*/
IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds,
in long durationNanos, in SessionTag tag, out @nullable SessionConfig config);
@@ -38,4 +42,12 @@ interface IHintManager {
void setHintSessionThreads(in IHintSession hintSession, in int[] tids);
int[] getHintSessionThreadIds(in IHintSession hintSession);
+
+ /**
+ * Returns FMQ channel information for the caller, which it associates to a binder token.
+ *
+ * Throws IllegalStateException if FMQ channel creation fails.
+ */
+ ChannelConfig getSessionChannel(in IBinder token);
+ oneway void closeSessionChannel();
}
diff --git a/core/java/android/tracing/inputmethod/InputMethodDataSource.java b/core/java/android/tracing/inputmethod/InputMethodDataSource.java
new file mode 100644
index 000000000000..5c5ad6947e4d
--- /dev/null
+++ b/core/java/android/tracing/inputmethod/InputMethodDataSource.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tracing.inputmethod;
+
+import android.annotation.NonNull;
+import android.tracing.perfetto.DataSource;
+import android.tracing.perfetto.DataSourceInstance;
+import android.tracing.perfetto.StartCallbackArguments;
+import android.tracing.perfetto.StopCallbackArguments;
+import android.util.proto.ProtoInputStream;
+
+/**
+ * @hide
+ */
+public final class InputMethodDataSource
+ extends DataSource<DataSourceInstance, Void, Void> {
+ public static final String DATA_SOURCE_NAME = "android.inputmethod";
+
+ @NonNull
+ private final Runnable mOnStartCallback;
+ @NonNull
+ private final Runnable mOnStopCallback;
+
+ public InputMethodDataSource(@NonNull Runnable onStart, @NonNull Runnable onStop) {
+ super(DATA_SOURCE_NAME);
+ mOnStartCallback = onStart;
+ mOnStopCallback = onStop;
+ }
+
+ @Override
+ public DataSourceInstance createInstance(ProtoInputStream configStream, int instanceIndex) {
+ return new DataSourceInstance(this, instanceIndex) {
+ @Override
+ protected void onStart(StartCallbackArguments args) {
+ mOnStartCallback.run();
+ }
+
+ @Override
+ protected void onStop(StopCallbackArguments args) {
+ mOnStopCallback.run();
+ }
+ };
+ }
+}
diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java
index 1afedc185c85..9503f4925e14 100644
--- a/core/java/android/view/ImeBackAnimationController.java
+++ b/core/java/android/view/ImeBackAnimationController.java
@@ -38,6 +38,8 @@ import android.window.OnBackAnimationCallback;
import com.android.internal.inputmethod.SoftInputShowHideReason;
+import java.io.PrintWriter;
+
/**
* Controller for IME predictive back animation
*
@@ -134,7 +136,9 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
@Override
public void onBackInvoked() {
- if (!isBackAnimationAllowed()) {
+ if (!isBackAnimationAllowed() || !mIsPreCommitAnimationInProgress) {
+ // play regular hide animation if back-animation is not allowed or if insets control has
+ // been cancelled by the system (this can happen in split screen for example)
mInsetsController.hide(ime());
return;
}
@@ -269,4 +273,24 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
return mPostCommitAnimator != null && mTriggerBack;
}
+ /**
+ * Dump information about this ImeBackAnimationController
+ *
+ * @param prefix the prefix that will be prepended to each line of the produced output
+ * @param writer the writer that will receive the resulting text
+ */
+ public void dump(String prefix, PrintWriter writer) {
+ final String innerPrefix = prefix + " ";
+ writer.println(prefix + "ImeBackAnimationController:");
+ writer.println(innerPrefix + "mLastProgress=" + mLastProgress);
+ writer.println(innerPrefix + "mTriggerBack=" + mTriggerBack);
+ writer.println(innerPrefix + "mIsPreCommitAnimationInProgress="
+ + mIsPreCommitAnimationInProgress);
+ writer.println(innerPrefix + "mStartRootScrollY=" + mStartRootScrollY);
+ writer.println(innerPrefix + "isBackAnimationAllowed=" + isBackAnimationAllowed());
+ writer.println(innerPrefix + "isAdjustPan=" + isAdjustPan());
+ writer.println(innerPrefix + "isHideAnimationInProgress="
+ + isHideAnimationInProgress());
+ }
+
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c54526747c5c..f1cb4103f008 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1799,8 +1799,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.println("InsetsController:");
- mState.dump(prefix + " ", pw);
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + "InsetsController:");
+ mState.dump(innerPrefix, pw);
+ pw.println(innerPrefix + "mIsPredictiveBackImeHideAnimInProgress="
+ + mIsPredictiveBackImeHideAnimInProgress);
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 7dc151d8f9ee..71199e9c3619 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -234,7 +234,7 @@ public final class PointerIcon implements Parcelable {
}
int typeIndex = getSystemIconTypeIndex(type);
- if (typeIndex == 0) {
+ if (typeIndex < 0) {
typeIndex = getSystemIconTypeIndex(TYPE_DEFAULT);
}
@@ -606,7 +606,7 @@ public final class PointerIcon implements Parcelable {
case TYPE_HANDWRITING:
return com.android.internal.R.styleable.Pointer_pointerIconHandwriting;
default:
- return 0;
+ return -1;
}
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a23df799da59..1d70d18ac4c8 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -986,7 +986,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
updateBackgroundVisibility(surfaceUpdateTransaction);
updateBackgroundColor(surfaceUpdateTransaction);
- if (mLimitedHdrEnabled && hdrHeadroomChanged) {
+ if (mLimitedHdrEnabled && (hdrHeadroomChanged || creating)) {
surfaceUpdateTransaction.setDesiredHdrHeadroom(
mBlastSurfaceControl, mHdrHeadroom);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9579614ac379..60ad926f2be1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,7 +40,6 @@ import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout;
import static android.view.flags.Flags.sensitiveContentAppProtection;
-import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly;
@@ -32230,7 +32229,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
void increaseSensitiveViewsCount() {
if (mSensitiveViewsCount == 0) {
- mViewRootImpl.notifySensitiveContentAppProtection(true);
+ mViewRootImpl.addSensitiveContentAppProtection();
}
mSensitiveViewsCount++;
}
@@ -32238,11 +32237,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
void decreaseSensitiveViewsCount() {
mSensitiveViewsCount--;
if (mSensitiveViewsCount == 0) {
- if (sensitiveContentPrematureProtectionRemovedFix()) {
- mViewRootImpl.removeSensitiveContentProtectionOnTransactionCommit();
- } else {
- mViewRootImpl.notifySensitiveContentAppProtection(false);
- }
+ mViewRootImpl.removeSensitiveContentAppProtection();
}
if (mSensitiveViewsCount < 0) {
Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1d843757489e..fdf3cb119a42 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -25,6 +25,7 @@ import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.DragEvent.ACTION_DRAG_LOCATION;
+import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
import static android.view.InputDevice.SOURCE_CLASS_NONE;
import static android.view.InsetsSource.ID_IME;
import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT;
@@ -4244,7 +4245,14 @@ public final class ViewRootImpl implements ViewParent,
mReportNextDraw = false;
mLastReportNextDrawReason = null;
mActiveSurfaceSyncGroup = null;
- mHasPendingTransactions = false;
+ if (mHasPendingTransactions) {
+ // TODO: We shouldn't ever actually hit this, it means mPendingTransaction wasn't
+ // merged with a sync group or BLASTBufferQueue before making it to this point
+ // But better a one or two frame flicker than steady-state broken from dropping
+ // whatever is in this transaction
+ mPendingTransaction.apply();
+ mHasPendingTransactions = false;
+ }
mSyncBuffer = false;
if (isInWMSRequestedSync()) {
mWmsRequestSyncGroup.markSyncReady();
@@ -4331,29 +4339,42 @@ public final class ViewRootImpl implements ViewParent,
* <li>It should only notify service to unblock projection when all sensitive view are
* removed from the window.
* </ol>
+ *
+ * @param enableProtection if true, the protection is enabled for this window.
+ * if false, the protection is removed for this window.
*/
- void notifySensitiveContentAppProtection(boolean showSensitiveContent) {
+ private void applySensitiveContentAppProtection(boolean enableProtection) {
try {
if (mSensitiveContentProtectionService == null) {
return;
}
if (DEBUG_SENSITIVE_CONTENT) {
Log.d(TAG, "Notify sensitive content, package=" + mContext.getPackageName()
- + ", token=" + getWindowToken() + ", flag=" + showSensitiveContent);
+ + ", token=" + getWindowToken() + ", flag=" + enableProtection);
}
// The window would be blocked during screen share if it shows sensitive content.
mSensitiveContentProtectionService.setSensitiveContentProtection(
- getWindowToken(), mContext.getPackageName(), showSensitiveContent);
+ getWindowToken(), mContext.getPackageName(), enableProtection);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to protect sensitive content during screen share", ex);
}
}
/**
- * Sensitive protection is removed on transaction commit to avoid prematurely removing
- * the protection.
+ * Add sensitive content protection, when there are one or more visible sensitive views.
*/
- void removeSensitiveContentProtectionOnTransactionCommit() {
+ void addSensitiveContentAppProtection() {
+ applySensitiveContentAppProtection(true);
+ }
+
+ /**
+ * Remove sensitive content protection, when there is no visible sensitive view.
+ */
+ void removeSensitiveContentAppProtection() {
+ if (!sensitiveContentPrematureProtectionRemovedFix()) {
+ applySensitiveContentAppProtection(false);
+ return;
+ }
if (DEBUG_SENSITIVE_CONTENT) {
Log.d(TAG, "Add transaction to remove sensitive content protection, package="
+ mContext.getPackageName() + ", token=" + getWindowToken());
@@ -4361,7 +4382,7 @@ public final class ViewRootImpl implements ViewParent,
Transaction t = new Transaction();
t.addTransactionCommittedListener(mExecutor, () -> {
if (mAttachInfo.mSensitiveViewsCount == 0) {
- notifySensitiveContentAppProtection(false);
+ applySensitiveContentAppProtection(false);
}
});
applyTransactionOnDraw(t);
@@ -5279,10 +5300,12 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_CONTENT_CAPTURE) {
Log.v(mTag, "performContentCaptureInitialReport() on " + rootView);
}
+ boolean traceDispatchCapture = false;
try {
if (!isContentCaptureEnabled()) return;
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ traceDispatchCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
+ if (traceDispatchCapture) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for "
+ getClass().getSimpleName());
}
@@ -5298,7 +5321,9 @@ public final class ViewRootImpl implements ViewParent,
// Content capture is a go!
rootView.dispatchInitialProvideContentCaptureStructure();
} finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ if (traceDispatchCapture) {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
}
}
@@ -5306,10 +5331,12 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_CONTENT_CAPTURE) {
Log.v(mTag, "handleContentCaptureFlush()");
}
+ boolean traceFlushContentCapture = false;
try {
if (!isContentCaptureEnabled()) return;
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ traceFlushContentCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
+ if (traceFlushContentCapture) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for "
+ getClass().getSimpleName());
}
@@ -5321,7 +5348,9 @@ public final class ViewRootImpl implements ViewParent,
}
ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
} finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ if (traceFlushContentCapture) {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
}
}
@@ -7771,6 +7800,7 @@ public final class ViewRootImpl implements ViewParent,
mWindowAttributes.type)) {
// set the frame rate to the maximum value.
mIsTouchBoosting = true;
+ setPreferredFrameRateCategory(mLastPreferredFrameRateCategory);
}
/**
* We want to lower the refresh rate when MotionEvent.ACTION_UP,
@@ -9579,6 +9609,8 @@ public final class ViewRootImpl implements ViewParent,
mOnBackInvokedDispatcher.dump(prefix, writer);
+ mImeBackAnimationController.dump(prefix, writer);
+
writer.println(prefix + "View Hierarchy:");
dumpViewHierarchy(innerPrefix, writer, mView);
}
@@ -12635,10 +12667,12 @@ public final class ViewRootImpl implements ViewParent,
view = mFrameRateCategoryView;
}
+ boolean traceFrameRateCategory = false;
try {
if (frameRateCategory != FRAME_RATE_CATEGORY_DEFAULT
&& mLastPreferredFrameRateCategory != frameRateCategory) {
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ traceFrameRateCategory = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
+ if (traceFrameRateCategory) {
String reason = reasonToString(frameRateReason);
String sourceView = view == null ? "-" : view;
String category = categoryToString(frameRateCategory);
@@ -12656,7 +12690,9 @@ public final class ViewRootImpl implements ViewParent,
} catch (Exception e) {
Log.e(mTag, "Unable to set frame rate category", e);
} finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ if (traceFrameRateCategory) {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
}
}
@@ -12696,9 +12732,11 @@ public final class ViewRootImpl implements ViewParent,
return;
}
+ boolean traceFrameRate = false;
try {
if (mLastPreferredFrameRate != preferredFrameRate) {
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ traceFrameRate = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
+ if (traceFrameRate) {
Trace.traceBegin(
Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
+ preferredFrameRate + " compatibility "
@@ -12713,7 +12751,9 @@ public final class ViewRootImpl implements ViewParent,
} catch (Exception e) {
Log.e(mTag, "Unable to set frame rate", e);
} finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ if (traceFrameRate) {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
}
}
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index a2f3544c70ab..5aaa994f3f8f 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -374,7 +374,7 @@ public class AnimationSet extends Animation {
final Animation a = mAnimations.get(i);
temp.clear();
- a.getTransformationAt(interpolatedTime, t);
+ a.getTransformationAt(interpolatedTime, temp);
t.compose(temp);
}
}
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index de31667c96cb..812ecd158b18 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -78,6 +78,7 @@ public class Transformation {
mHasClipRect = false;
mAlpha = 1.0f;
mTransformationType = TYPE_BOTH;
+ mInsets = Insets.NONE;
}
/**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c7df15c7d5fa..bfe4e6f3cc9b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1592,7 +1592,8 @@ public final class AutofillManager {
// request comes in but PCC Detection hasn't been triggered. There is no benefit to
// trigger PCC Detection separately in those cases.
if (!isActiveLocked()) {
- final boolean clientAdded = tryAddServiceClientIfNeededLocked();
+ final boolean clientAdded =
+ tryAddServiceClientIfNeededLocked(isCredmanRequested);
if (clientAdded) {
startSessionLocked(/* id= */ AutofillId.NO_AUTOFILL_ID, /* bounds= */ null,
/* value= */ null, /* flags= */ FLAG_PCC_DETECTION);
@@ -1850,7 +1851,8 @@ public final class AutofillManager {
Rect bounds, AutofillValue value, int flags) {
if (shouldIgnoreViewEnteredLocked(id, flags)) return null;
- final boolean clientAdded = tryAddServiceClientIfNeededLocked();
+ boolean credmanRequested = isCredmanRequested(view);
+ final boolean clientAdded = tryAddServiceClientIfNeededLocked(credmanRequested);
if (!clientAdded) {
if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): no service client");
return null;
@@ -2645,6 +2647,11 @@ public final class AutofillManager {
*/
@GuardedBy("mLock")
private boolean tryAddServiceClientIfNeededLocked() {
+ return tryAddServiceClientIfNeededLocked(/*credmanRequested=*/ false);
+ }
+
+ @GuardedBy("mLock")
+ private boolean tryAddServiceClientIfNeededLocked(boolean credmanRequested) {
final AutofillClient client = getClient();
if (client == null) {
return false;
@@ -2659,7 +2666,7 @@ public final class AutofillManager {
final int userId = mContext.getUserId();
final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.addClient(mServiceClient, client.autofillClientGetComponentName(),
- userId, receiver);
+ userId, receiver, credmanRequested);
int flags = 0;
try {
flags = receiver.getIntResult();
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index cefd6dc13005..1a9322e6f2b8 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -38,7 +38,7 @@ import com.android.internal.os.IResultReceiver;
oneway interface IAutoFillManager {
// Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
void addClient(in IAutoFillManagerClient client, in ComponentName componentName, int userId,
- in IResultReceiver result);
+ in IResultReceiver result, boolean credmanRequested);
void removeClient(in IAutoFillManagerClient client, int userId);
void startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 12bd45af7ffb..c0d31fae4b8f 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -54,7 +54,7 @@ flag {
is_fixed_read_only: true
metadata {
purpose: PURPOSE_BUGFIX
- }
+ }
}
flag {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0e7de48cc7da..a073873cb2a0 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2461,6 +2461,7 @@ public final class InputMethodManager {
* @hide
*/
public boolean hideSoftInputFromView(@NonNull View view, @HideFlags int flags) {
+ checkFocus();
final boolean isFocusedAndWindowFocused = view.hasWindowFocus() && view.isFocused();
synchronized (mH) {
final boolean hasServedByInputMethod = hasServedByInputMethodLocked(view);
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 5c113f865d45..461eab61e393 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -18,6 +18,7 @@ package android.window;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -93,6 +94,19 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
@TaskFragmentTransitionType
public static final int TASK_FRAGMENT_TRANSIT_CHANGE = TRANSIT_CHANGE;
+
+ /**
+ * The task fragment drag resize transition used by activity embedding.
+ *
+ * This value is also used in Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE and must not
+ * conflict with other predefined transition types.
+ *
+ * @hide
+ */
+ @WindowManager.TransitionType
+ @TaskFragmentTransitionType
+ public static final int TASK_FRAGMENT_TRANSIT_DRAG_RESIZE = TRANSIT_FIRST_CUSTOM + 17;
+
/**
* Introduced a sub set of {@link WindowManager.TransitionType} for the types that are used for
* TaskFragment transition.
@@ -106,6 +120,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
TASK_FRAGMENT_TRANSIT_OPEN,
TASK_FRAGMENT_TRANSIT_CLOSE,
TASK_FRAGMENT_TRANSIT_CHANGE,
+ TASK_FRAGMENT_TRANSIT_DRAG_RESIZE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface TaskFragmentTransitionType {}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index e8b4f0bec6a8..760c9166959c 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -71,3 +71,10 @@ flag {
description: "Enables quick switch for desktop mode"
bug: "338066529"
}
+
+flag {
+ name: "enable_additional_windows_above_status_bar"
+ namespace: "lse_desktop_experience"
+ description: "Allows for additional windows tied to WindowDecoration to be layered between status bar and notification shade."
+ bug: "316186265"
+}
diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig
index 33af48636f02..69cac6f3dfa5 100644
--- a/core/java/android/window/flags/responsible_apis.aconfig
+++ b/core/java/android/window/flags/responsible_apis.aconfig
@@ -49,3 +49,10 @@ flag {
description: "Prevent BAL based on it is bound by foreground Uid but the app switch is stopped."
bug: "283801068"
}
+
+flag {
+ name: "bal_improved_metrics"
+ namespace: "responsible_apis"
+ description: "Improved metrics."
+ bug: "339245692"
+}
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 945164a7f25f..4d1b87a3d97a 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -120,4 +120,11 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "pip_restore_to_overlay"
+ description: "Restore exit-pip activity back to ActivityEmbedding overlay"
+ bug: "297887697"
} \ No newline at end of file
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 3af1dd7a28e4..ad7329485a0e 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -166,6 +166,13 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
}
/**
+ * Same as {@link #onPackageAdded(String, int)}, but this callback
+ * has extras passed in.
+ */
+ public void onPackageAddedWithExtras(String packageName, int uid, Bundle extras) {
+ }
+
+ /**
* Called when a package is really removed (and not replaced).
*/
@UnsupportedAppUsage
@@ -173,19 +180,47 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
}
/**
+ * Same as {@link #onPackageRemoved(String, int)}, but this callback
+ * has extras passed in.
+ */
+ public void onPackageRemovedWithExtras(String packageName, int uid, Bundle extras) {
+ }
+
+ /**
* Called when a package is really removed (and not replaced) for
* all users on the device.
*/
public void onPackageRemovedAllUsers(String packageName, int uid) {
}
+ /**
+ * Same as {@link #onPackageRemovedAllUsers(String, int)}, but this callback
+ * has extras passed in.
+ */
+ public void onPackageRemovedAllUsersWithExtras(String packageName, int uid, Bundle extras) {
+ }
+
public void onPackageUpdateStarted(String packageName, int uid) {
}
+ /**
+ * Same as {@link #onPackageUpdateStarted(String, int)}, but this callback
+ * has extras passed in.
+ */
+ public void onPackageUpdateStartedWithExtras(String packageName, int uid, Bundle extras) {
+ }
+
public void onPackageUpdateFinished(String packageName, int uid) {
}
/**
+ * Same as {@link #onPackageUpdateFinished(String, int)}, but this callback
+ * has extras passed in.
+ */
+ public void onPackageUpdateFinishedWithExtras(String packageName, int uid, Bundle extras) {
+ }
+
+ /**
* Direct reflection of {@link Intent#ACTION_PACKAGE_CHANGED
* Intent.ACTION_PACKAGE_CHANGED} being received, informing you of
* changes to the enabled/disabled state of components in a package
@@ -283,6 +318,13 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
}
/**
+ * Same as {@link #onPackageModified(String)}, but this callback
+ * has extras passed in.
+ */
+ public void onPackageModifiedWithExtras(@NonNull String packageName, Bundle extras) {
+ }
+
+ /**
* Called when a package in the stopped state is started for some reason.
*
* @param packageName Name of the package that was unstopped
@@ -425,10 +467,13 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
mModifiedPackages = mTempArray;
mChangeType = PACKAGE_UPDATING;
onPackageUpdateFinished(pkg, uid);
+ onPackageUpdateFinishedWithExtras(pkg, uid, intent.getExtras());
onPackageModified(pkg);
+ onPackageModifiedWithExtras(pkg, intent.getExtras());
} else {
mChangeType = PACKAGE_PERMANENT_CHANGE;
onPackageAdded(pkg, uid);
+ onPackageAddedWithExtras(pkg, uid, intent.getExtras());
}
onPackageAppearedWithExtras(pkg, intent.getExtras());
onPackageAppeared(pkg, mChangeType);
@@ -442,11 +487,13 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
mChangeType = PACKAGE_UPDATING;
onPackageUpdateStarted(pkg, uid);
+ onPackageUpdateStartedWithExtras(pkg, uid, intent.getExtras());
if (intent.getBooleanExtra(Intent.EXTRA_ARCHIVAL, false)) {
// In case it is a removal event due to archiving, we trigger package
// update event to refresh details like icons, title etc. corresponding to
// the archived app.
onPackageModified(pkg);
+ onPackageModifiedWithExtras(pkg, intent.getExtras());
}
} else {
mChangeType = PACKAGE_PERMANENT_CHANGE;
@@ -455,8 +502,10 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
// it when it is re-added.
mSomePackagesChanged = true;
onPackageRemoved(pkg, uid);
+ onPackageRemovedWithExtras(pkg, uid, intent.getExtras());
if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) {
onPackageRemovedAllUsers(pkg, uid);
+ onPackageRemovedAllUsersWithExtras(pkg, uid, intent.getExtras());
}
}
onPackageDisappearedWithExtras(pkg, intent.getExtras());
@@ -476,6 +525,7 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
}
onPackageChangedWithExtras(pkg, intent.getExtras());
onPackageModified(pkg);
+ onPackageModifiedWithExtras(pkg, intent.getExtras());
}
} else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
String pkg = getPackageName(intent);
diff --git a/core/java/com/android/internal/inputmethod/ImeTracing.java b/core/java/com/android/internal/inputmethod/ImeTracing.java
index ee9c3aa57d72..cd4ccdad6f58 100644
--- a/core/java/com/android/internal/inputmethod/ImeTracing.java
+++ b/core/java/com/android/internal/inputmethod/ImeTracing.java
@@ -60,7 +60,9 @@ public abstract class ImeTracing {
*/
public static ImeTracing getInstance() {
if (sInstance == null) {
- if (isSystemProcess()) {
+ if (android.tracing.Flags.perfettoIme()) {
+ sInstance = new ImeTracingPerfettoImpl();
+ } else if (isSystemProcess()) {
sInstance = new ImeTracingServerImpl();
} else {
sInstance = new ImeTracingClientImpl();
@@ -78,7 +80,7 @@ public abstract class ImeTracing {
* and {@see #IME_TRACING_FROM_IMS}
* @param where
*/
- public void sendToService(byte[] protoDump, int source, String where) {
+ protected void sendToService(byte[] protoDump, int source, String where) {
InputMethodManagerGlobal.startProtoDump(protoDump, source, where,
e -> Log.e(TAG, "Exception while sending ime-related dump to server", e));
}
diff --git a/core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java
new file mode 100644
index 000000000000..91b80ddaa836
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/ImeTracingPerfettoImpl.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import static android.tracing.perfetto.DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.internal.perfetto.protos.Inputmethodeditor.InputMethodClientsTraceProto;
+import android.internal.perfetto.protos.Inputmethodeditor.InputMethodManagerServiceTraceProto;
+import android.internal.perfetto.protos.Inputmethodeditor.InputMethodServiceTraceProto;
+import android.internal.perfetto.protos.TracePacketOuterClass.TracePacket;
+import android.internal.perfetto.protos.WinscopeExtensionsImplOuterClass.WinscopeExtensionsImpl;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.tracing.inputmethod.InputMethodDataSource;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
+import android.util.proto.ProtoOutputStream;
+import android.view.inputmethod.InputMethodManager;
+
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * An implementation of {@link ImeTracing} for perfetto tracing.
+ */
+final class ImeTracingPerfettoImpl extends ImeTracing {
+ private final AtomicInteger mTracingSessionsCount = new AtomicInteger(0);
+ private final AtomicBoolean mIsClientDumpInProgress = new AtomicBoolean(false);
+ private final AtomicBoolean mIsServiceDumpInProgress = new AtomicBoolean(false);
+ private final AtomicBoolean mIsManagerServiceDumpInProgress = new AtomicBoolean(false);
+ private final InputMethodDataSource mDataSource = new InputMethodDataSource(
+ mTracingSessionsCount::incrementAndGet,
+ mTracingSessionsCount::decrementAndGet);
+
+ ImeTracingPerfettoImpl() {
+ Producer.init(InitArguments.DEFAULTS);
+ mDataSource.register(
+ new DataSourceParams(PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT));
+ }
+
+
+ @Override
+ public void triggerClientDump(String where, InputMethodManager immInstance,
+ @Nullable byte[] icProto) {
+ if (!isEnabled() || !isAvailable()) {
+ return;
+ }
+
+ if (!mIsClientDumpInProgress.compareAndSet(false, true)) {
+ return;
+ }
+
+ if (immInstance == null) {
+ return;
+ }
+
+ try {
+ Trace.beginSection("inputmethod_client_dump");
+ mDataSource.trace((ctx) -> {
+ final ProtoOutputStream os = ctx.newTracePacket();
+ os.write(TracePacket.TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+ final long tokenWinscopeExtensions =
+ os.start(TracePacket.WINSCOPE_EXTENSIONS);
+ final long tokenExtensionsField =
+ os.start(WinscopeExtensionsImpl.INPUTMETHOD_CLIENTS);
+ os.write(InputMethodClientsTraceProto.WHERE, where);
+ final long tokenClient =
+ os.start(InputMethodClientsTraceProto.CLIENT);
+ immInstance.dumpDebug(os, icProto);
+ os.end(tokenClient);
+ os.end(tokenExtensionsField);
+ os.end(tokenWinscopeExtensions);
+ });
+ } finally {
+ mIsClientDumpInProgress.set(false);
+ Trace.endSection();
+ }
+ }
+
+ @Override
+ public void triggerServiceDump(String where,
+ @NonNull ServiceDumper dumper, @Nullable byte[] icProto) {
+ if (!isEnabled() || !isAvailable()) {
+ return;
+ }
+
+ if (!mIsServiceDumpInProgress.compareAndSet(false, true)) {
+ return;
+ }
+
+ try {
+ Trace.beginSection("inputmethod_service_dump");
+ mDataSource.trace((ctx) -> {
+ final ProtoOutputStream os = ctx.newTracePacket();
+ os.write(TracePacket.TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+ final long tokenWinscopeExtensions =
+ os.start(TracePacket.WINSCOPE_EXTENSIONS);
+ final long tokenExtensionsField =
+ os.start(WinscopeExtensionsImpl.INPUTMETHOD_SERVICE);
+ os.write(InputMethodServiceTraceProto.WHERE, where);
+ dumper.dumpToProto(os, icProto);
+ os.end(tokenExtensionsField);
+ os.end(tokenWinscopeExtensions);
+ });
+ } finally {
+ mIsServiceDumpInProgress.set(false);
+ Trace.endSection();
+ }
+ }
+
+ @Override
+ public void triggerManagerServiceDump(@NonNull String where, @NonNull ServiceDumper dumper) {
+ if (!isEnabled() || !isAvailable()) {
+ return;
+ }
+
+ if (!mIsManagerServiceDumpInProgress.compareAndSet(false, true)) {
+ return;
+ }
+
+ try {
+ Trace.beginSection("inputmethod_manager_service_dump");
+ mDataSource.trace((ctx) -> {
+ final ProtoOutputStream os = ctx.newTracePacket();
+ os.write(TracePacket.TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+ final long tokenWinscopeExtensions =
+ os.start(TracePacket.WINSCOPE_EXTENSIONS);
+ final long tokenExtensionsField =
+ os.start(WinscopeExtensionsImpl.INPUTMETHOD_MANAGER_SERVICE);
+ os.write(InputMethodManagerServiceTraceProto.WHERE, where);
+ dumper.dumpToProto(os, null);
+ os.end(tokenExtensionsField);
+ os.end(tokenWinscopeExtensions);
+ });
+ } finally {
+ mIsManagerServiceDumpInProgress.set(false);
+ Trace.endSection();
+ }
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mTracingSessionsCount.get() > 0;
+ }
+
+ @Override
+ public void startTrace(@Nullable PrintWriter pw) {
+ // Intentionally left empty. Tracing start/stop is managed through Perfetto.
+ }
+
+ @Override
+ public void stopTrace(@Nullable PrintWriter pw) {
+ // Intentionally left empty. Tracing start/stop is managed through Perfetto.
+ }
+
+ @Override
+ public void addToBuffer(ProtoOutputStream proto, int source) {
+ // Intentionally left empty. Only used for legacy tracing.
+ }
+}
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index f2d2c1b637c6..6ffa8261c8fd 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -134,10 +134,12 @@ public class Cuj {
public static final int CUJ_LAUNCHER_WIDGET_PICKER_SEARCH_BACK = 99;
public static final int CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK = 100;
public static final int CUJ_LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK = 101;
+ public static final int CUJ_LAUNCHER_PRIVATE_SPACE_LOCK = 102;
+ public static final int CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK = 103;
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
@VisibleForTesting
- static final int LAST_CUJ = CUJ_LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK;
+ static final int LAST_CUJ = CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK;
/** @hide */
@IntDef({
@@ -230,7 +232,9 @@ public class Cuj {
CUJ_LAUNCHER_TASKBAR_ALL_APPS_SEARCH_BACK,
CUJ_LAUNCHER_WIDGET_PICKER_CLOSE_BACK,
CUJ_LAUNCHER_WIDGET_PICKER_SEARCH_BACK,
- CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK
+ CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK,
+ CUJ_LAUNCHER_PRIVATE_SPACE_LOCK,
+ CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -335,6 +339,8 @@ public class Cuj {
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_WIDGET_PICKER_SEARCH_BACK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_WIDGET_PICKER_SEARCH_BACK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_LOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_LOCK;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_UNLOCK;
}
private Cuj() {
@@ -533,6 +539,10 @@ public class Cuj {
return "LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK";
case CUJ_LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK:
return "LAUNCHER_WIDGET_EDU_SHEET_CLOSE_BACK";
+ case CUJ_LAUNCHER_PRIVATE_SPACE_LOCK:
+ return "LAUNCHER_PRIVATE_SPACE_LOCK";
+ case CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK:
+ return "LAUNCHER_PRIVATE_SPACE_UNLOCK";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 66b0158fbd67..0734e6827d4d 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -886,9 +886,16 @@ public class LockPatternView extends View {
cellState.activationAnimator.cancel();
}
AnimatorSet animatorSet = new AnimatorSet();
+
+ // When running the line end animation (see doc for createLineEndAnimation), if cell is in:
+ // - activate state - use finger position at the time of hit detection
+ // - deactivate state - use current position where the end was last during initial animation
+ // Note that deactivate state will only come if mKeepDotActivated is themed true.
+ final float startX = activate == CELL_ACTIVATE ? mInProgressX : cellState.lineEndX;
+ final float startY = activate == CELL_ACTIVATE ? mInProgressY : cellState.lineEndY;
AnimatorSet.Builder animatorSetBuilder = animatorSet
.play(createLineDisappearingAnimation())
- .with(createLineEndAnimation(cellState, mInProgressX, mInProgressY,
+ .with(createLineEndAnimation(cellState, startX, startY,
getCenterXForColumn(cell.column), getCenterYForRow(cell.row)));
if (mDotSize != mDotSizeActivated) {
animatorSetBuilder.with(createDotRadiusAnimation(cellState));
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 0e3c51047b31..c7866524668f 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -235,6 +235,10 @@ bool JHwParcel::wasSent() const {
return mWasSent;
}
+void JHwParcel::addBlob(const sp<JHwBlob> &blob) {
+ mBlobs.emplace_back(blob);
+}
+
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -1059,6 +1063,7 @@ static void JHwParcel_native_writeBuffer(
JHwParcel::GetNativeContext(env, thiz)->getParcel();
sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, blobObj);
+ JHwParcel::GetNativeContext(env, thiz)->addBlob(blob);
status_t err = blob->writeToParcel(parcel);
if (err != OK) {
diff --git a/core/jni/android_os_HwParcel.h b/core/jni/android_os_HwParcel.h
index 2c26993a0439..07d144a7ef13 100644
--- a/core/jni/android_os_HwParcel.h
+++ b/core/jni/android_os_HwParcel.h
@@ -17,14 +17,15 @@
#ifndef ANDROID_OS_HW_PARCEL_H
#define ANDROID_OS_HW_PARCEL_H
-#include "hwbinder/EphemeralStorage.h"
-
#include <android-base/macros.h>
#include <hwbinder/IBinder.h>
#include <hwbinder/Parcel.h>
#include <jni.h>
#include <utils/RefBase.h>
+#include "android_os_HwBlob.h"
+#include "hwbinder/EphemeralStorage.h"
+
namespace android {
struct JHwParcel : public RefBase {
@@ -44,6 +45,8 @@ struct JHwParcel : public RefBase {
EphemeralStorage *getStorage();
+ void addBlob(const sp<JHwBlob> &blob);
+
void setTransactCallback(::android::hardware::IBinder::TransactCallback cb);
void send();
@@ -60,6 +63,7 @@ private:
::android::hardware::IBinder::TransactCallback mTransactCallback;
bool mWasSent;
+ std::vector<sp<JHwBlob>> mBlobs;
DISALLOW_COPY_AND_ASSIGN(JHwParcel);
};
diff --git a/core/res/res/layout/side_fps_toast.xml b/core/res/res/layout/side_fps_toast.xml
index 96860b050393..2c35c9b888cf 100644
--- a/core/res/res/layout/side_fps_toast.xml
+++ b/core/res/res/layout/side_fps_toast.xml
@@ -18,28 +18,26 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="350dp"
android:layout_gravity="center"
+ android:minWidth="350dp"
android:background="@color/side_fps_toast_background">
<TextView
- android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="6"
android:text="@string/fp_power_button_enrollment_title"
- android:singleLine="true"
- android:ellipsize="end"
android:textColor="@color/side_fps_text_color"
android:paddingLeft="20dp"/>
<Space
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
+ android:layout_width="5dp"
+ android:layout_height="match_parent" />
<Button
android:id="@+id/turn_off_screen"
- android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="3"
android:text="@string/fp_power_button_enrollment_button_text"
- android:paddingRight="20dp"
style="?android:attr/buttonBarNegativeButtonStyle"
android:textColor="@color/side_fps_button_color"
- android:maxLines="1"/>
+ />
</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e1f5f87310e5..b65fc5f4e890 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Roetinemodus-inligtingkennisgewing"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Batterybespaarder is aangeskakel"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Verminder tans batterygebruik om batterylewe te verleng"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Batterybespaarder is aan"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Batterybespaarder is aangeskakel om batterylewe te verleng"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterybespaarder"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterybespaarder is afgeskakel"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Foon se battery het genoeg krag. Kenmerke is nie meer beperk nie."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f97a2bc98269..cef77b026c83 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"የዕለት ተዕለት ሁነታ መረጃ ማሳወቂያዎች"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"የባትሪ ኃይል ቆጣቢ በርቷል"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"የባትሪ ዕድሜን ለማራዘም የባትሪ አጠቃቀምን በመቀነስ ላይ"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ባትሪ ቆጣቢ በርቷል"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"የባትሪ ዕድሜን ለማራዘም የባትሪ ኃይል ቆጣቢ በርቷል"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ባትሪ ቆጣቢ"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"የባትሪ ቆጣቢ ጠፍቷል"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ስልክ በቂ የባትሪ ኃይል አለው። ባህሪያት ከእንግዲህ የተገደቡ አይደሉም።"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ሥራ 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"ሙከራ"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"የጋራ"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"የሥራ መገለጫ"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"የግል ቦታ"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"አባዛ"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"የጋራ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"አደገኛ የማሳወቂያ ይዘት ተደብቋል"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ለደኅንነት ሲባል የመተግበሪያ ይዘት ከማያ ገጽ ማጋራት ተደብቋል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 190a3ff07c3a..2a5822a5fa1c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2148,10 +2148,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"إشعار معلومات \"وضع سلسلة الإجراءات\""</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"تم تفعيل ميزة توفير شحن البطارية"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"يتم تقليل استخدام البطارية لإطالة عمرها."</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"تم تفعيل ميزة \"توفير شحن البطارية\""</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"تم تفعيل ميزة \"توفير شحن البطارية\" لإطالة عمر البطارية"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"توفير شحن البطارية"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"تم تفعيل ميزة \"توفير شحن البطارية\""</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"تم شحن الهاتف بدرجة كافية وتفعيل الميزات مرة أخرى"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 72eb2cc0b4db..6e0da5454350 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ৰুটিন ম’ডৰ তথ্য জাননী"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"বেটাৰী সঞ্চয়কাৰী অন কৰা হৈছে"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ বেটাৰীৰ ব্যৱহাৰ কমোৱা হৈছে"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"বেটাৰী সঞ্চয়কাৰী অন কৰা হৈছে"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ বেটাৰী সঞ্চয়কাৰী অন কৰা হৈছে"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"বেটাৰী সঞ্চয়কাৰী"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"বেটাৰী সঞ্চয়কাৰী অফ কৰা হ’ল"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ফ\'নটোত পর্যাপ্ত পৰিমাণে চার্জ আছে। সুবিধাবোৰ আৰু সীমাবদ্ধ কৰা নাই।"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"কৰ্মস্থান ৩"</string>
<string name="profile_label_test" msgid="9168641926186071947">"পৰীক্ষা"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"শ্বেয়াৰ কৰা"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"কৰ্মস্থানৰ প্ৰ’ফাইল"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্ৰাইভেট স্পে’চ"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্ল’ন"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"সম্প্ৰদায়ৰ সৈতে জড়িত"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল জাননী লুকুওৱা হৈছে"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"সুৰক্ষাৰ বাবে এপৰ সমল স্ক্ৰীণ শ্বেয়াৰ কৰাৰ পৰা লুকুৱাই ৰখা হৈছে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 3f99b5dc2c6c..a3d4423ea772 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rejim üçün məlumat bildirişi"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Enerjiyə Qənaət aktivdir"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Batareyanın ömrünü uzatmaq üçün batareyadan istifadəni azaldın"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Enerjiyə Qənaət yanılıdır"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Batareya istifadəsini artırmaq üçün Enerjiyə Qənaət yandırıldı"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Enerjiyə qənaət"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Enerjiyə qənaət deaktivdir"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonun kifayət qədər enerjisi var. Funksiyalar artıq məhdud deyil."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Kommunal"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"İş profili"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Məxfi sahə"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Kommunal"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Həssas bildiriş kontenti gizlədildi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Güvənlik üçün tətbiq kontenti ekran paylaşımından gizlədildi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 471befa4e13c..fff999ac57c4 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obaveštenje o informacijama Rutinskog režima"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Ušteda baterije je uključena"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Smanjuje se potrošnja baterije da bi se produžilo njeno trajanje"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Ušteda baterije je uključena"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Ušteda baterije je uključena da bi se produžilo trajanje baterije"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Ušteda baterije"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Ušteda baterije je isključena"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterija telefona je dovoljno napunjena. Funkcije više nisu ograničene."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index a8b0344a2ce6..19ca1c4da054 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2146,10 +2146,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Апавяшчэнне з інфармацыяй пра ўсталяваны рэжым"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Рэжым энергазберажэння ўключаны"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Абмежаванне выкарыстання зараду для падаўжэння часу працы ад акумулятара"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Рэжым энергазберажэння ўключаны"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Каб падоўжыць час працы ад акумулятара, уключаны рэжым энергазберажэння"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Рэжым энергазберажэння"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Рэжым эканоміі зараду выключаны"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"У тэлефона дастатковы ўзровень зараду. Функцыі больш не абмежаваны."</string>
@@ -2405,14 +2403,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Працоўны 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Тэставы"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Супольны"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Працоўны профіль"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Прыватная прастора"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Супольны"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Канфідэнцыяльнае змесціва ў апавяшчэннях схавана"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Змесціва праграмы выключана з абагульвання экрана ў мэтах бяспекі"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2adebe258082..2f1ecdbbbb91 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известие с информация за режима на поредица"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Режимът за запазване на батерията е включен"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Използването на батерията се намалява с цел удължаване на живота ѝ"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Режимът за запазване на батерията е включен"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Режимът за запазване на батерията е включен с цел удължаване на живота ѝ"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Режим за запазване на батерията"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Режимът за запазване на батерията е изключен"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Батерията на телефона има достатъчно заряд. Функциите вече не са ограничени."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Служебни 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Тестване"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Общи"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Служебен потребителски профил"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частно пространство"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониране"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Общи"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Деликатното съдържание в известието е скрито"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Съдържанието на приложението е скрито от функцията за споделяне на екрана от съображения за сигурност"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index aa061a9448d2..f1ebfb02faa5 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"রুটিন মোডের তথ্য সংক্রান্ত বিজ্ঞপ্তি"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"\'ব্যাটারি সেভার\' ফিচার চালু করা হয়েছে"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ব্যাটারির আয়ু বাড়াতে ব্যাটারির ব্যবহার কমানো হচ্ছে"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"\'ব্যাটারি সেভার\' চালু করা হয়েছে"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ব্যাটারির আয়ু বাড়াতে \'ব্যাটারি সেভার\' চালু করা হয়েছে"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ব্যাটারি সেভার"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ব্যাটারি সেভার বন্ধ করা আছে"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ফোনের ব্যাটারিতে যথেষ্ট চার্জ আছে। ফিচারগুলির উপর আর বিধিনিষেধ নেই।"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"৩য় অফিস"</string>
<string name="profile_label_test" msgid="9168641926186071947">"পরীক্ষা"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"কমিউনাল"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"অফিস প্রোফাইল"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্রাইভেট স্পেস"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্লোন"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"কমিউনাল"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল বিজ্ঞপ্তির কন্টেন্ট লুকানো আছে"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"নিরাপত্তার জন্য স্ক্রিন শেয়ার করা থেকে লুকানো অ্যাপের কন্টেন্ট"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 6ea579d13f3b..1212af9c2a24 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještenje za informacije Rutinskog načina"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Ušteda baterije je uključena"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Smanjena je potrošnja baterije da se produži vijek trajanja baterije"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Ušteda baterije je uključena"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Ušteda baterije je uključena radi produženja vijeka trajanja baterije"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Ušteda baterije"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Ušteda baterije je isključena"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon se dovoljno napunio. Funkcije nisu više ograničene."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"3. poslovno"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Testno"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Opće"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Radni profil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Opće"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sakriven je osjetljiv sadržaj obavještenja"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je sakriven od dijeljenja ekrana radi sigurnosti"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 1778a3b3aa8e..f2447791a65a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificació d\'informació del mode de rutina"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Estalvi de bateria s\'ha activat"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"S\'està reduint l\'ús de la bateria per allargar-ne la durada"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"La funció Estalvi de bateria està activada"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"S\'ha activat la funció Estalvi de bateria per allargar la durada de la bateria"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Estalvi de bateria"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"L\'estalvi de bateria s\'ha desactivat"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"El telèfon té prou bateria. Les funcions ja no estan restringides."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4e0938c121fc..6b0426729a1d 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2146,10 +2146,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informační oznámení režimu sledu činností"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Zapnul se spořič baterie"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Je třeba snížit využití baterie za účelem prodloužení její výdrže"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Spořič baterie je zapnutý"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Spořič baterie je zapnutý a prodlužuje výdrž baterie"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Spořič baterie"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Spořič baterie je vypnutý"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon je dostatečně nabitý. Funkce už nejsou omezeny."</string>
@@ -2405,14 +2403,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Práce 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Komunální"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Pracovní profil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Soukromý prostor"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Komunální"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivých oznámení je skrytý"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikace je z bezpečnostních důvodů při sdílení obrazovky skryt"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 286adca93d3f..9bd374ae12e9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikation med oplysninger om rutinetilstand"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Batterisparefunktion er aktiveret"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reducerer batteriforbruget for at forlænge batteritiden"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Batterisparefunktion er aktiveret"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterisparefunktion"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterisparefunktion blev slået fra"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonen har tilstrækkeligt batteri. Funktionerne er ikke længere begrænsede."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6c5783a0e0f2..24a71b5ca45d 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Infomitteilung zum Ablaufmodus"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Energiesparmodus aktiviert"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reduzierung der Akkunutzung, um die Akkulaufzeit zu verlängern"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Energiesparmodus ist aktiviert"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Der Energiesparmodus ist aktiviert, um die Akkulaufzeit zu verlängern"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Energiesparmodus"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Energiesparmodus deaktiviert"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Das Smartphone ist ausreichend geladen. Es sind keine Funktionen mehr beschränkt."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Geschäftlich 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Gemeinsam genutzt"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Arbeitsprofil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Vertrauliches Profil"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeinsam genutzt"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Vertrauliche Benachrichtigungsinhalte ausgeblendet"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-Inhalte werden aus Sicherheitsgründen bei der Bildschirmfreigabe ausgeblendet"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 80a4ef2395f6..32611ef20d39 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ειδοποίηση πληροφοριών λειτουργίας Ρουτίνας"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Μείωση της χρήσης της μπαταρίας για παράταση της διάρκειας ζωής της μπαταρίας"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε για την παράταση της διάρκειας ζωής της μπαταρίας"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Εξοικονόμηση μπαταρίας"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Η Εξοικονόμηση μπαταρίας απενεργοποιήθηκε"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Το τηλέφωνο είναι αρκετά φορτισμένο. Οι λειτουργίες δεν περιορίζονται πλέον."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Εργασία 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Δοκιμή"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Κοινόχρηστο"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Προφίλ εργασίας"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Απόρρητος χώρος"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Κλώνος"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Κοινόχρηστο"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Έγινε απόκρυψη της ειδοποίησης ευαίσθητου περιεχομένου"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Για λόγους ασφάλειας, έγινε απόκρυψη του περιεχομένου της εφαρμογής από την κοινή χρήση οθόνης"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a2c2a7c846de..1e1a6873ae4d 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Battery Saver turned on"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reducing battery usage to extend battery life"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Battery Saver is on"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Battery Saver is turned on to extend battery life"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Battery Saver"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Battery Saver turned off"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Phone has enough charge. Features no longer restricted."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 8d3920404cbf..9951afd5137f 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Battery Saver turned on"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reducing battery usage to extend battery life"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Battery Saver is on"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Battery Saver is turned on to extend battery life"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Battery Saver"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Battery Saver turned off"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Phone has enough charge. Features no longer restricted."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 967eb6827fbe..8d5568169d33 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Battery Saver turned on"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reducing battery usage to extend battery life"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Battery Saver is on"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Battery Saver is turned on to extend battery life"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Battery Saver"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Battery Saver turned off"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Phone has enough charge. Features no longer restricted."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 997ccbd8ea9f..a8e397d5b054 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Battery Saver turned on"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reducing battery usage to extend battery life"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Battery Saver is on"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Battery Saver is turned on to extend battery life"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Battery Saver"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Battery Saver turned off"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Phone has enough charge. Features no longer restricted."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 151df50bed6a..e7f713bb8822 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‎‎‎Routine Mode info notification‎‏‎‎‏‎"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎Battery Saver turned on‎‏‎‎‏‎"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎Reducing battery usage to extend battery life‎‏‎‎‏‎"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎Battery Saver is on‎‏‎‎‏‎"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎Battery Saver is turned on to extend battery life‎‏‎‎‏‎"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎Battery Saver‎‏‎‎‏‎"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‏‎Battery Saver turned off‎‏‎‎‏‎"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‎Phone has enough charge. Features no longer restricted.‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index dd90f0360d4b..5d4e95121033 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación de información del modo de Rutinas"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Ahorro de batería activado"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reduciendo el uso de la batería para extender su duración"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"El Ahorro de batería está activado"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Se activó el Ahorro de batería para extender la duración de batería"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Ahorro de batería"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Se desactivó el Ahorro de batería"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"El teléfono tiene suficiente carga. Ya no se restringen las funciones."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Trabajo 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Probar"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabajo"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Compartido"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Se ocultó contenido sensible de la notificación"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Se ocultó el contenido de la app durante el uso compartido de la pantalla por motivos de seguridad"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3be0785b2091..19be81f0f4f9 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación sobre el modo rutina"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Ahorro de batería activado"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reduciendo el uso de batería para prolongar su duración"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Ahorro de batería activado"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Se ha activado Ahorro de batería para prolongar la duración de la batería"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Ahorro de batería"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Ahorro de batería desactivado"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"El teléfono tiene suficiente batería. Las funciones ya no están restringidas."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1e1eb1cdb535..4a17e0db6c84 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutiinirežiimi teabe märguanne"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Akusäästja lülitati sisse"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Aku tööea pikendamiseks vähendatakse akukasutust"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Akusäästja on sisse lülitatud"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Akusäästja on sisse lülitatud, et pikendada aku tööiga"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akusäästja"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akusäästja on välja lülitatud"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon on piisavalt laetud. Funktsioonid ei ole enam piiratud."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index eccb4b12bcc2..3f3404c56b8e 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -467,9 +467,9 @@
<string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"Igorpen iraunkorrak egiteko baimena ematen dio aplikazioari. Igorpena amaitu ondoren ere igortzen jarraitzen dute igorpen iraunkorrek. Gehiegi erabiliz gero, Android TV gailua motel edo ezegonkor ibiliko da, memoria gehiago erabiliko delako."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"Igorpen iraunkorrak emateko baimena ematen dio aplikazioari; horiek igorpena amaitu ondoren mantentzen dira. Gehiegi erabiliz gero, telefonoa motel edo ezegonkor ibiliko da, memoria gehiago erabiliko delako."</string>
<string name="permlab_readContacts" msgid="8776395111787429099">"irakurri kontaktuak"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Tabletan gordetako kontaktuei buruzko datuak irakurtzeko baimena ematen dio aplikazioari. Kontaktuak sortu dituzten tabletako kontuak ere atzitu ahalko ditu aplikazioak. Horrek barnean hartuko ditu instalatutako aplikazioak sortutako kontuak, agian. Baimen horrekin, kontaktuen datuak gorde ditzake aplikazioak, eta baliteke asmo txarreko aplikazioek zuk jakin gabe partekatzea datu horiek."</string>
- <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Android TV gailuan gordetako kontaktuei buruzko datuak irakurtzeko baimena ematen dio aplikazioari. Kontaktuak sortu dituzten Android TV gailuko kontuak ere atzitu ahalko ditu aplikazioak. Horrek barnean hartuko ditu instalatutako aplikazioak sortutako kontuak, agian. Baimen horrekin, kontaktuen datuak gorde ditzake aplikazioak, eta baliteke asmo txarreko aplikazioek zuk jakin gabe partekatzea datu horiek."</string>
- <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Telefonoan gordetako kontaktuei buruzko datuak irakurtzeko baimena ematen dio aplikazioari. Kontaktuak sortu dituzten telefonoko kontuak ere atzitu ahalko ditu aplikazioak. Horrek barnean hartuko ditu instalatutako aplikazioak sortutako kontuak, agian. Baimen horrekin, kontaktuen datuak gorde ditzake aplikazioak, eta baliteke asmo txarreko aplikazioek zuk jakin gabe partekatzea datu horiek."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Tabletan biltegiratutako kontaktuei buruzko datuak irakurtzeko baimena ematen dio aplikazioari. Kontaktuak sortu dituzten tabletako kontuak ere atzitu ahalko ditu aplikazioak. Horrek barnean hartuko ditu instalatutako aplikazioak sortutako kontuak, agian. Baimen horrekin, kontaktuen datuak gorde ditzake aplikazioak, eta baliteke asmo txarreko aplikazioek zuk jakin gabe partekatzea datu horiek."</string>
+ <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Android TV gailuan biltegiratutako kontaktuei buruzko datuak irakurtzeko baimena ematen dio aplikazioari. Kontaktuak sortu dituzten Android TV gailuko kontuak ere atzitu ahalko ditu aplikazioak. Horrek barnean hartuko ditu instalatutako aplikazioak sortutako kontuak, agian. Baimen horrekin, kontaktuen datuak gorde ditzake aplikazioak, eta baliteke asmo txarreko aplikazioek zuk jakin gabe partekatzea datu horiek."</string>
+ <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Telefonoan biltegiratutako kontaktuei buruzko datuak irakurtzeko baimena ematen dio aplikazioari. Kontaktuak sortu dituzten telefonoko kontuak ere atzitu ahalko ditu aplikazioak. Horrek barnean hartuko ditu instalatutako aplikazioak sortutako kontuak, agian. Baimen horrekin, kontaktuen datuak gorde ditzake aplikazioak, eta baliteke asmo txarreko aplikazioek zuk jakin gabe partekatzea datu horiek."</string>
<string name="permlab_writeContacts" msgid="8919430536404830430">"aldatu kontaktuak"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"Tabletan gordetako kontaktuei buruzko datuak aldatzeko baimena ematen dio aplikazioari. Baimen horrekin, aplikazioak kontaktuen datuak ezaba ditzake."</string>
<string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Android TV gailuan gordetako kontaktuei buruzko datuak aldatzeko baimena ematen dio aplikazioari. Baimen horrekin, aplikazioak kontaktuen datuak ezaba ditzake."</string>
@@ -485,9 +485,9 @@
<string name="permlab_bodySensors_background" msgid="4912560779957760446">"Atzitu gorputz-sentsoreen datuak (adib., bihotz-maiztasunarenak) atzeko planoan"</string>
<string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Aplikazioa atzeko planoan egon bitartean, gorputz-sentsoreen datuak (besteak beste, bihotz-maiztasuna, tenperatura eta odolean dagoen oxigenoaren ehunekoa) erabiltzeko baimena ematen dio aplikazioari."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"irakurri egutegiko gertaerak eta xehetasunak"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Aplikazioak tabletan gordetako egutegiko gertaerak irakur ditzake eta egutegiko datuak parteka eta gorde ditzake."</string>
- <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Aplikazioak Android TV gailuan gordeta dituzun egutegiko gertaerak irakur ditzake, baita egutegiko datuak partekatu eta gorde ere."</string>
- <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Aplikazioak telefonoan gordetako egutegiko gertaerak irakur ditzake eta egutegiko datuak parteka eta gorde ditzake."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Aplikazioak tabletan biltegiratutako egutegiko gertaerak irakur ditzake eta egutegiko datuak parteka eta gorde ditzake."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Aplikazioak Android TV gailuan biltegiratuta dituzun egutegiko gertaerak irakur ditzake, baita egutegiko datuak partekatu eta gorde ere."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Aplikazioak telefonoan biltegiratutako egutegiko gertaerak irakur ditzake eta egutegiko datuak parteka eta gorde ditzake."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"gehitu edo aldatu egutegiko gertaerak eta bidali mezu elektronikoak gonbidatuei jabeek jakin gabe"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Tabletako gertaerak gehitzeko, kentzeko edo aldatzeko aukera du aplikazioak. Gainera, egutegien jabeenak diruditen mezuak bidal ditzake, eta gertaerak alda ditzake jabeei beraiei jakinarazi gabe."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Android TV gailuan egutegiko gertaerak gehitzeko eta gehitutakoak kentzeko edo aldatzeko aukera dute aplikazioek. Gainera, egutegien jabeenak diruditen mezuak bidal ditzakete, edo gertaerak aldatu jabeei ezer esan gabe."</string>
@@ -2403,14 +2403,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Lanekoa 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Probakoa"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Partekatua"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Laneko profila"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Eremu pribatua"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Partekatua"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Jakinarazpenaren kontuzko edukia ezkutatu da"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aplikazioko edukia ezkutatu egin da pantaila partekatzeko eginbidetik, segurtasuna bermatzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f2ee5f194332..3f850c12c9c2 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"اعلان اطلاعات حالت روال معمول"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"«بهینه‌سازی باتری» روشن شد"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"برای افزایش عمر باتری، مصرف باتری کاهش می‌یابد"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"«بهینه‌سازی باتری» روشن است"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"«بهینه‌سازی باتری» برای افزایش عمر باتری روشن شد"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"بهینه‌سازی باتری"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"«بهینه‌سازی باتری» خاموش شد"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"تلفن به‌اندازه کافی شارژ دارد. ویژگی‌ها دیگر محدود نمی‌شوند."</string>
@@ -2397,20 +2395,16 @@
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"صفحه‌کلیدهای فیزیکی پیکربندی شدند"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"برای مشاهده صفحه‌کلیدها ضربه بزنید"</string>
<string name="profile_label_private" msgid="6463418670715290696">"خصوصی"</string>
- <string name="profile_label_clone" msgid="769106052210954285">"مشابه‌سازی"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"همسانه‌سازی"</string>
<string name="profile_label_work" msgid="3495359133038584618">"کار"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"کار ۲"</string>
<string name="profile_label_work_3" msgid="4834572253956798917">"کار ۳"</string>
<string name="profile_label_test" msgid="9168641926186071947">"آزمایش"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"عمومی"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"نمایه کاری"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"فضای خصوصی"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"همسانه‌سازی"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"همگانی"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"محتوای اعلان حساس پنهان شده است"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"به‌دلایل امنیتی، محتوای برنامه از دید هم‌رسانی صفحه‌نمایش پنهان شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 053b66587e50..3e1adc44b0c3 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohjelmatilan tietoilmoitus"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Virransäästö päällä"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Akun käyttöä rajoitetaan akunkeston pidentämiseksi"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Virransäästö on päällä"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Virransäästö on laitettu päälle akunkeston pidentämiseksi"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Virransäästö"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Virransäästö laitettiin pois päältä"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Puhelimessa on tarpeeksi virtaa. Ominaisuuksia ei enää rajoiteta."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Työ 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Testi"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Jaettu"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Työprofiili"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Yksityinen tila"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klooni"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Yhteinen"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Arkaluontoisen ilmoituksen sisältö piilotettu"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sovelluksen sisältö piilotettu näytön jakamiselta turvallisuussyistä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index de1343c21cce..dd968e1ec185 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -252,7 +252,7 @@
<string name="reboot_safemode_title" msgid="5853949122655346734">"Redémarrer en mode sans échec"</string>
<string name="reboot_safemode_confirm" msgid="1658357874737219624">"Voulez-vous redémarrer en mode sans échec? Cette opération aura pour effet de désactiver toutes les applications tierces que vous avez installées. Elles seront réactivées au prochain redémarrage."</string>
<string name="recent_tasks_title" msgid="8183172372995396653">"Récents"</string>
- <string name="no_recent_tasks" msgid="9063946524312275906">"Aucune application récente"</string>
+ <string name="no_recent_tasks" msgid="9063946524312275906">"Aucune appli récente"</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"Options de la tablette"</string>
<string name="global_actions" product="tv" msgid="3871763739487450369">"Options d\'Android TV"</string>
<string name="global_actions" product="default" msgid="6410072189971495460">"Options du téléphone"</string>
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Économiseur de pile activé"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Réduction de l\'utilisation de la pile pour en prolonger l\'autonomie"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"La fonctionnalité Économiseur de pile est activée"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"La fonctionnalité Économiseur de pile est activée pour prolonger l\'autonomie de la pile"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Économiseur de pile"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Le mode Économiseur de pile est désactivé"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Le téléphone est suffisamment chargé. Ces fonctionnalités ne sont plus restreintes."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Professionnel 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil professionnel"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu confidentiel de la notification est masqué"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'application est masqué du Partage d\'écran par mesure de sécurité"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 31ee078f615f..96636dcd3c60 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Économiseur de batterie activé"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Réduction de l\'utilisation de la batterie pour prolonger son autonomie"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Économiseur de batterie activé"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"L\'économiseur de batterie est activé pour prolonger l\'autonomie de la batterie"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Économiseur de batterie"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Économiseur de batterie désactivé"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Téléphone suffisamment chargé. Les fonctionnalités ne sont plus restreintes."</string>
@@ -2406,7 +2404,7 @@
<string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string>
<string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil professionnel"</string>
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string>
- <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Cloner"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu sensible de la notification a été masqué"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index f3b0a18c781f..85ad42fe8ff5 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación da información do modo de rutina"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Activouse Aforro de batería"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Estase limitando o uso da batería para aumentar a súa duración"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"A función Aforro de batería está activada"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Activouse a función Aforro de batería para prolongar a duración"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Aforro de batería"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Desactivouse a función Aforro de batería."</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"O teléfono non ten suficiente batería. Xa non se restrinxirán as funcións."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index e4fe84567734..82ffb2f55c9d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"રૂટિન મોડની માહિતીનું નોટિફિકેશન"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"બૅટરી સેવરની સુવિધા ચાલુ કરી છે"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"બૅટરીની આવરદા વધારવા માટે બૅટરીનો વપરાશ ઘટાડી રહ્યાં છીએ"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"બૅટરી સેવર ચાલુ છે"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર ચાલુ કરવામાં આવ્યું છે"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"બૅટરી સેવર"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"બૅટરી સેવર બંધ કર્યું"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ફોનમાં પૂરતો ચાર્જ છે. સુવિધાઓ હવે મર્યાદિત નથી."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 716fabfe73bf..8772cdc62a11 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"रूटीन मोड जानकारी की सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"बैटरी सेवर चालू है"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"इससे बैटरी कम खर्च होती है और बैटरी लाइफ़ बढ़ती है"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"बैटरी सेवर चालू है"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"बैटरी लाइफ़ बढ़ाने के लिए बैटरी सेवर चालू किया गया है"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"बैटरी सेवर"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"बैटरी सेवर बंद कर दिया गया है"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"फ़ोन में काफ़ी बैटरी बची है. सुविधाओं पर अब पाबंदी नहीं है."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ऑफ़िस 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"टेस्ट"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"कम्यूनिटी"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"वर्क प्रोफ़ाइल"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"प्राइवेट स्पेस"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"कम्यूनिटी"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील जानकारी वाली सूचना का कॉन्टेंट छिपा है"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेयर करने के दौरान सुरक्षा के लिए, ऐप्लिकेशन का कॉन्टेंट छिपाया गया"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 9c110279a773..88bc29fc3a3c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještavanje o informacijama u Rutinskom načinu rada"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Uključena je štednja baterije"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Smanjuje se potrošnja baterije radi produženja njezinog trajanja"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Štednja baterije je uključena"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Štednja baterije je uključena da bi se produljilo trajanje baterije"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Štednja baterije"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Isključena je Štednja baterije"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterija mobilnog telefona dovoljno je napunjena. Značajke više nisu ograničene."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Posao 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Radni profil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Zajedničko"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Skriven je osjetljiv sadržaj obavijesti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije sakriven je od dijeljenja zaslona radi sigurnosti"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 1e9cedff2936..f7e4a8f6ffe9 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Információs értesítés a rutinmódról"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Akkumulátorkímélő mód bekapcsolva"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Akkuhasználat csökkentése a hosszabb akkumulátor-élettartam érdekében"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Akkumulátorkímélő mód bekapcsolva"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Az akkumulátor-üzemidő meghosszabbítása érdekében bekapcsolódott az Akkumulátorkímélő mód"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akkumulátorkímélő mód"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akkumulátorkímélő mód kikapcsolva"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"A telefon töltöttsége elegendő. A funkciók használata már nincs korlátozva."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 96b943b56d89..251646c15031 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ծանուցում լիցքավորման մասին"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Մարտկոցի տնտեսումը միացվել է"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Մարտկոցի օգտագործումը նվազեցվել է դրա աշխատաժամանակը երկարացնելու համար"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Մարտկոցի տնտեսումը միացված է"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Մարտկոցի տնտեսումը միացվել է՝ մարտկոցի աշխատաժամանակը երկարացնելու համար"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Մարտկոցի տնտեսում"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Մարտկոցի տնտեսումն անջատված է"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Հեռախոսի լիցքը բավարար է։ Գործառույթներն այլևս չեն սահմանափակվում։"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e3a93c83eeaf..139b4ab8338b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikasi info Mode Rutinitas"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Penghemat Baterai diaktifkan"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Mengurangi penggunaan baterai untuk memperpanjang masa pakai baterai"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Penghemat Baterai aktif"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Penghemat Baterai diaktifkan untuk memperpanjang daya tahan baterai"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Penghemat Baterai"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Penghemat Baterai dinonaktifkan"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterai ponsel cukup terisi. Fitur tidak lagi dibatasi."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Pengujian"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil kerja"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang privasi"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Konten notifikasi sensitif disembunyikan"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Konten aplikasi disembunyikan dari berbagi layar untuk alasan keamanan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 78cc1458cb46..1f55241f1363 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upplýsingatilkynning aðgerðastillingar"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Kveikt á rafhlöðusparnaði"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Dregur úr rafhlöðunotkun til að auka endingu rafhlöðunnar"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Kveikt er á rafhlöðusparnaði"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Kveikt er á rafhlöðusparnaði til að lengja rafhlöðuendingu"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Rafhlöðusparnaður"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Slökkt á rafhlöðusparnaði"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Síminn er með næga hleðslu. Eiginleikar eru ekki lengur takmarkaðir."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 057f037ed825..2f066b5f46cb 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifica di informazioni sulla modalità Routine"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Risparmio energetico attivato"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Riduzione dell\'utilizzo di batteria per estenderne la durata"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Risparmio energetico attivo"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Risparmio energetico è attivo per aumentare la durata della batteria"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Risparmio energetico"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Risparmio energetico disattivato"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Il telefono ha carica sufficiente. Funzionalità non più limitate."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Lavoro 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Condiviso"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profilo di lavoro"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spazio privato"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Condiviso"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Contenuti sensibili della notifica nascosti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenuti dell\'app nascosti dalla condivisione schermo per sicurezza"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 2525b08ca226..3fc962acc9a7 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"התראת מידע לגבי מצב שגרתי"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"התכונה \'חיסכון בסוללה\' הופעלה"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"הפחתת השימוש בסוללה תאריך את חיי הסוללה"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"החיסכון בסוללה מופעל"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"מצב \'חיסכון בסוללה\' מופעל כדי להאריך את חיי הסוללה"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"חיסכון בסוללה"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"מצב \'חיסכון בסוללה\' כבוי"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"הטלפון טעון מספיק. התכונות כבר לא מוגבלות."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"פרופיל עבודה 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"בדיקה"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"שיתופי"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"פרופיל העבודה"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"המרחב הפרטי"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"שכפול"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"שיתופי"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"יש תוכן רגיש בהתראה שהוסתר"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"תוכן האפליקציה מוסתר משיתוף המסך מטעמי אבטחה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 5c96e97b2b91..db3ba5a49246 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ルーティン モード情報の通知"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"バッテリー セーバーが ON になりました"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"バッテリー使用量を減らし、バッテリー駆動時間を延ばします"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"バッテリー セーバーが ON になっています"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"バッテリーを長持ちさせるためにバッテリー セーバーが ON になっています"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"バッテリー セーバー"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"バッテリー セーバーが OFF になりました"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"スマートフォンが十分に充電されました。機能は制限されなくなりました。"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"仕事用 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"テスト"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"仕事用プロファイル"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"プライベート スペース"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"プライベートな通知内容は表示されません"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"セキュリティ上、画面共有ではアプリの内容は非表示となります"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2f7a81b150cf..97003c4fd11b 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"რუტინის რეჟიმის საინფორმაციო შეტყობინება"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ბატარეის დამზოგველი ჩართულია"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ბატარეის მოხმარების შემცირება ბატარეის მუშაობის გახანგრძლივების მიზნით"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ბატარეის დამზოგი ჩართულია"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ბატარეის მუშაობის გასახანგრძლივებლად ჩართულია ბატარეის დამზოგი"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ბატარეის დამზოგი"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ბატარეის დამზოგი გამორთულია"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ტელეფონი საკმარისად არის დატენილი. ფუნქციები შეზღუდული აღარ არის."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"სამსახური 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"სატესტო"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"საერთო"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"სამსახურის პროფილი"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"კერძო სივრცე"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"კლონის შექმნა"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"საერთო"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"სენსიტიური შეტყობინების კონტენტი დამალულია"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ეკრანის გაზიარებიდან აპის კონტენტი დამალულია უსაფრთხოების მიზნით"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 1b1f0022c12b..116166d5c3c9 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1964,7 +1964,7 @@
<string name="maximize_button_text" msgid="4258922519914732645">"Жазу"</string>
<string name="close_button_text" msgid="10603510034455258">"Жабу"</string>
<string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
- <string name="call_notification_answer_action" msgid="5999246836247132937">"Жауап"</string>
+ <string name="call_notification_answer_action" msgid="5999246836247132937">"Жауап беру"</string>
<string name="call_notification_answer_video_action" msgid="2086030940195382249">"Бейне"</string>
<string name="call_notification_decline_action" msgid="3700345945214000726">"Қабылдамау"</string>
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"Тұтқаны қою"</string>
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режим туралы хабарландыру"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Батареяны үнемдеу режимі қосулы"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Батарея шығынын азайтсаңыз, батареяның жұмысы ұзарады."</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Батареяны үнемдеу режимі қосулы"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Батарея жұмысының ұзақтығын арттыру үшін батареяны үнемдеу режимі қосылған."</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Батареяны үнемдеу режимі"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Батареяны үнемдеу режимі өшірілді"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Телефонның заряды жеткілікті. Функцияларға енді шектеу қойылмайды."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 6555b27d4534..456256c1432c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ការ​ជូនដំណឹង​ព័ត៌មាន​របស់​មុខងារ​ទម្លាប់"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"បានបើកមុខងារ​សន្សំ​ថ្ម"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ការកាត់បន្ថយការប្រើប្រាស់ថ្ម ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"មុខងារ​សន្សំ​ថ្មត្រូវបានបើក"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"មុខងារ​សន្សំ​ថ្មត្រូវបានបើក ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"មុខងារ​សន្សំ​ថ្ម"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"មុខងារ​សន្សំ​ថ្ម​ត្រូវបានបិទ"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ទូរសព្ទ​មាន​កម្រិតថ្ម​គ្រប់គ្រាន់​។ មុខងារ​ផ្សេងៗ​មិន​ត្រូវបាន​រឹតបន្តឹងទៀត​ទេ។"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ការងារទី 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"ការធ្វើ​តេស្ត"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"ទូទៅ"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"កម្រងព័ត៌មានការងារ"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"លំហ​ឯកជន"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ក្លូន"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ទូទៅ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"បានលាក់ខ្លឹមសារជូនដំណឹងដែលមានលក្ខណៈរសើប"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"បានលាក់ខ្លឹមសារកម្មវិធីពីការបង្ហាញ​អេក្រង់ដើម្បីសុវត្ថិភាព"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 9d7d8c4f4742..97f013638877 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ದೈನಂದಿನ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯ ನೋಟಿಫಿಕೇಶನ್"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು ಬ್ಯಾಟರಿ ಬಳಕೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಆಗಿದೆ"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು ಬ್ಯಾಟರಿ ಸೇವರ್ ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ಬ್ಯಾಟರಿ ಸೇವರ್"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಅನ್ನು ಆಫ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ಫೋನ್‌ನಲ್ಲಿ ಸಾಕಷ್ಟು ಚಾರ್ಜ್ ಇದೆ. ಇನ್ನು ಮುಂದೆ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗುವುದಿಲ್ಲ."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ಕೆಲಸ 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"ಪರೀಕ್ಷೆ"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"ಸಮುದಾಯ"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ಕ್ಲೋನ್"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ಸಮುದಾಯ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ಸೂಕ್ಷ್ಮ ನೋಟಿಫಿಕೇಶನ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ಭದ್ರತೆಗಾಗಿ ಸ್ಕ್ರೀನ್‌‌ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯಲ್ಲಿ ಆ್ಯಪ್ ಕಂಟೆಂಟ್‌ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index e76ccc954ad5..df29128d17ed 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"루틴 모드 정보 알림"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"절전 모드 사용 설정됨"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"배터리 사용량을 줄여서 배터리 수명을 늘립니다."</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"절전 모드 사용 중"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"배터리 수명을 늘리기 위해 절전 모드가 사용 설정되었습니다"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"절전 모드"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"절전 모드가 사용 중지되었습니다"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"휴대전화의 배터리가 충분하므로 기능이 더 이상 제한되지 않습니다"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"직장 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"테스트"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"공동"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"직장 프로필"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"비공개 스페이스"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"클론"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"공동"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"민감한 알림 콘텐츠 숨김"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"보안을 위해 화면 공유에서 앱 콘텐츠가 숨겨집니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index f2469f29f228..9511db4fd9d3 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режимдин адаттагы билдирмеси"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Батареяны үнөмдөгүч күйгүзүлдү"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Кубат үнөмдөлсө, батарея көбүрөөк убакытка жетет"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Батареяны үнөмдөгүч режими күйүк"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Батареянын кубатынын мөөнөтүн узартуу үчүн Батареяны үнөмдөгүч режими күйгүзүлдү"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Батареяны үнөмдөгүч"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Батареяны үнөмдөө режими өчүк"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Телефондун кубаты жетиштүү. Функциялар мындан ары чектелбейт."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index b27be696f249..a0aded4e183d 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ການແຈ້ງເຕືອນຂໍ້ມູນໂໝດກິດຈະວັດປະຈຳວັນ"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີແລ້ວ"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ກຳລັງຫຼຸດການໃຊ້ແບັດເຕີຣີເພື່ອຍືດອາຍຸແບັດເຕີຣີ"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ຕົວປະຢັດແບັດເຕີຣີເປີດຢູ່"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ຕົວປະຢັດແບັດເຕີຣີເປີດຢູ່ເພື່ອຍືດອາຍຸແບັດເຕີຣີ"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ຕົວປະຢັດແບັດເຕີຣີ"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ປິດຕົວປະຢັດແບັດເຕີຣີແລ້ວ"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ໂທລະສັບມີໄຟພຽງພໍແລ້ວ. ບໍ່ມີການຈຳກັດຄຸນສົມບັດອີກຕໍ່ໄປແລ້ວ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 28d8e25d674f..837bff76ecf2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2146,10 +2146,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Veiksmų sekos režimo informacijos pranešimas"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Įjungta akumuliatoriaus tausojimo priemonė"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Sumažinamas akumuliatoriaus energijos vartojimas, kad akumuliatorius veiktų ilgiau"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Akumuliatoriaus tausojimo priemonė įjungta, kad akumuliatorius veiktų ilgiau"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akumuliatoriaus tausojimo priemonė"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akumuliatoriaus tausojimo priemonė išjungta"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonas pakankamai įkrautas. Funkcijos neberibojamos."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index b745ff43eb68..4e244734f340 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatīvs paziņojums par akumulatoru"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Tiek samazināts akumulatora lietojums, lai paildzinātu akumulatora darbību."</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Akumulatora enerģijas taupīšanas režīms ir ieslēgts"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Akumulatora enerģijas taupīšanas režīms ir ieslēgts, lai paildzinātu akumulatora darbību."</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akumulatora enerģijas taupīšanas režīms"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akumulatora enerģijas taupīšanas režīms ir izslēgts"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Tālruņa uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 646f2a18688b..3790be062ec2 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известување за информации за режимот за рутини"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"„Штедачот на батерија“ е вклучен"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Се намалува користењето на батеријата за нејзино подолго траење"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"„Штедачот на батерија“ е вклучен"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"„Штедачот на батерија“ е вклучен за да се продолжи траењето на батеријата"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Штедач на батерија"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Штедачот на батерија е исклучен"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Телефонот е доволно полн. Функциите веќе не се ограничени."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Работен профил 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Профил за тестирање"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Профил на заедницата"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Работен профил"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватен простор"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониран профил"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Профил на заедницата"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Содржината на чувствителните известувања е скриена"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Од безбедносни причини, содржините на апликацијата се скриени од споделувањето екран"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index a763c273a325..563efdb47efd 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ദിനചര്യ മോഡ് വിവരത്തെ കുറിച്ചുള്ള അറിയിപ്പ്"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ബാറ്ററി സേവർ ഓണാക്കി"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ബാറ്ററി ലൈഫ് വർദ്ധിപ്പിക്കാൻ ബാറ്ററി ഉപയോഗം കുറയ്ക്കുന്നു"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ബാറ്ററി സേവർ ഓണാണ്"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ബാറ്ററി ലൈഫ് വർദ്ധിപ്പിക്കാൻ ബാറ്ററി സേവർ ഓണാക്കിയിരിക്കുന്നു"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ബാറ്ററി ലാഭിക്കൽ"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കിയിരിക്കുന്നു"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ഫോണിൽ വേണ്ടത്ര ചാർജ് ഉണ്ട്. ഫീച്ചറുകൾക്ക് ഇനി നിയന്ത്രണമില്ല."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 6f5e4b82e37b..afde064d48f9 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Хэвшлийн горимын мэдээллийн мэдэгдэл"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Батарей хэмнэгчийг асаасан"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Батарейн ажиллах хугацааг уртасгахын тулд батарей ашиглалтыг багасгаж байна"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Батарей хэмнэгч асаалттай байна"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Батарей хэмнэгчийг батарейн ажиллах хугацааг уртасгахын тулд асаасан"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Батарей хэмнэгч"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Батарей хэмнэгчийг унтраалаа"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Утас хангалттай цэнэгтэй боллоо. Онцлогуудыг цаашид хязгаарлахгүй."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 9c9e072c2285..8e8d354a3a5b 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनक्रम मोडची माहिती सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"बॅटरी सेव्हर सुरू केला आहे"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी वापर कमी करा"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"बॅटरी सेव्हर सुरू आहे"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर सुरू केले आहे"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"बॅटरी सेव्‍हर"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"बॅटरी सेव्हर बंद केलेला आहे"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"फोन पुरेसा चार्ज केलेला आहे. वैशिष्ट्ये मर्यादित नाहीत."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index c0ba454f6b5b..fe4ab56b7975 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Pemberitahuan maklumat Mod Rutin"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Penjimat Bateri dihidupkan"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Mengurangkan penggunaan bateri untuk melanjutkan hayat bateri"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Penjimat Bateri dihidupkan"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Penjimat Bateri dihidupkan untuk melanjutkan hayat bateri"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Penjimat Bateri"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Penjimat Bateri dimatikan"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Cas telefon mencukupi. Ciri tidak lagi dihadkan."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Ujian"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil kerja"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang privasi"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Kandungan pemberitahuan yang sensitif disembunyikan"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Kandungan apl disembunyikan daripada perkongsian skrin untuk keselamatan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 305cfc7493fe..5f5b0ab61661 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ပုံမှန်မုဒ်အတွက် အချက်အလက်ပြသည့် အကြောင်းကြားချက်"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ဘက်ထရီ အားထိန်း ဖွင့်ထားသည်"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် ဘက်ထရီ အသုံးပြုမှု လျှော့ချခြင်း"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"‘ဘက်ထရီ အားထိန်း’ ဖွင့်ထားသည်"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ဘက်ထရီ သက်တမ်းရှည်စေရန် ‘ဘက်ထရီ အားထိန်း’ ဖွင့်ထားသည်"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ဘက်ထရီ အားထိန်း"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ဘက်ထရီ အားထိန်းကို ပိတ်ထားသည်"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ဖုန်းတွင် ဘက်ထရီအား အလုံအလောက် ရှိသည်။ လုပ်ဆောင်ချက်များကို ကန့်သတ်မထားတော့ပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 1625c858377f..c4c705c5a942 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Varsel med informasjon om rutinemodus"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Batterisparing er slått på"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reduserer batteribruken for å forlenge batterilevetiden"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Batterisparing er på"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Batterisparing er slått på for å forlenge batterilevetiden"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterisparing"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterisparing er slått av"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonen har nok batteri. Funksjoner begrenses ikke lenger."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Jobb 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Felles"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Jobbprofil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Felles"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitivt varselinnhold er skjult"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av sikkerhetsgrunner er appinnholdet skjult for skjermdelingen"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index d0647985776c..559f07a3e6da 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -84,7 +84,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"मोबाइल नेटवर्कमाथि पहुँच राख्न सकिएन"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"रुचाइएको नेटवर्क परिवर्तन गरी हेर्नुहोस्‌। परिवर्तन गर्न ट्याप गर्नुहोस्‌।"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"आपत्‌कालीन कल सेवा अनुपलब्ध छ"</string>
- <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"आपत्कालीन कलहरू गर्न मोबाइल नेटवर्क चाहिन्छ"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"आपत्‌कालीन कलहरू गर्न मोबाइल नेटवर्क चाहिन्छ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"अलर्टहरू"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"कल फर्वार्ड गर्ने सेवा"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"आपत्‌कालीन कलब्याक मोड"</string>
@@ -652,7 +652,7 @@
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रिन लक प्रयोग गर्नुहोस्"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"जारी राख्न आफ्नो स्क्रिन लक हाल्नुहोस्"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरमा बेसरी थिच्नुहोस्"</string>
- <string name="fingerprint_acquired_insufficient" msgid="2410176550915730974">"फिंगरप्रिन्ट पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="fingerprint_acquired_insufficient" msgid="2410176550915730974">"फिंगरप्रिन्ट मिलेन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिन्ट सेन्सर सफा गरेर फेरि प्रयास गर्नुहोस्"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर सफा गरेर फेरि प्रयास गर्नुहोस्"</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरमा बेसरी थिच्नुहोस्"</string>
@@ -664,8 +664,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"हरेक पटक आफ्नो औँला थोरै यताउता सार्नुहोस्"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_error_not_match" msgid="4599441812893438961">"फिंगरप्रिन्ट पहिचान गर्न सकिएन"</string>
- <string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फिंगरप्रिन्ट पहिचान गर्न सकिएन"</string>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"फिंगरप्रिन्ट मिलेन"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फिंगरप्रिन्ट मिलेन"</string>
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"अनुहार प्रमाणीकरण गरियो"</string>
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनचर्या मोडको जानकारीमूलक सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ब्याट्री सेभर अन गरिएको छ"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ब्याट्रीको आयु बढाउन ब्याट्रीको खपत कम गरिँदै छ"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ब्याट्री सेभर अन छ"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ब्याट्रीको आयु बढाउन ब्याट्री सेभर अन गरिएको छ"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ब्याट्री सेभर"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ब्याट्री सेभर अफ गरियो"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"फोनमा पर्याप्त चार्ज छ। सुविधाहरूलाई अब उप्रान्त प्रतिबन्ध लगाइँदैन।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ae1d5373319e..5c393af52d37 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatiemelding voor routinemodus"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Batterijbesparing staat aan"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Het batterijgebruik wordt beperkt om de batterijduur te verlengen"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Batterijbesparing staat aan"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Batterijbesparing is aangezet om de batterijduur te verlengen"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterijbesparing"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterijbesparing staat uit"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefoon is voldoende opgeladen. Functies worden niet meer beperkt."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Werk 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Gemeenschappelijk"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Werkprofiel"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privégedeelte"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeenschappelijk"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Content van gevoelige meldingen verborgen"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-content verborgen voor scherm delen vanwege beveiligingsrisico\'s"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 181e7b19e593..e6fa56248b0f 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ନିୟମିତ ମୋଡ୍‍ ସୂଚନା ବିଜ୍ଞପ୍ତି"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ବେଟେରୀ ସେଭର ଚାଲୁ କରାଯାଇଛି"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ବ୍ୟାଟେରୀ ଲାଇଫ ବଢ଼ାଇବା ପାଇଁ ବ୍ୟାଟେରୀ ବ୍ୟବହାର କମ୍ କରିବା"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ବ୍ୟାଟେରୀ ସେଭର୍‌ ଚାଲୁ‌ ଅଛି"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ବେଟେରୀ ଲାଇଫକୁ ବଢ଼ାଇବା ପାଇଁ ବେଟେରୀ ସେଭରକୁ ଚାଲୁ କରାଯାଇଛି"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ବେଟେରୀ ସେଭର"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ବ୍ୟାଟେରୀ ସେଭର୍ ବନ୍ଦ ଅଛି"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ଫୋନରେ ଯଥେଷ୍ଟ ଚାର୍ଜ ଅଛି। ଫିଚରଗୁଡ଼ିକ ଆଉ ପ୍ରତିବନ୍ଧିତ ନୁହେଁ।"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ୱାର୍କ 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"ଟେଷ୍ଟ"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"କମ୍ୟୁନାଲ"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ୱାର୍କ ପ୍ରୋଫାଇଲ"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"କ୍ଲୋନ"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"କମ୍ୟୁନାଲ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ସମ୍ୱେଦନଶୀଳ ବିଜ୍ଞପ୍ତି ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ସୁରକ୍ଷା ପାଇଁ ସ୍କ୍ରିନ ସେୟାରରୁ ଆପ ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 598af1d4f17d..e2586e6a9b78 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ਨਿਯਮਬੱਧ ਮੋਡ ਦੀ ਜਾਣਕਾਰੀ ਵਾਲੀ ਸੂਚਨਾ"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੈਟਰੀ ਵਰਤੋਂ ਨੂੰ ਘਟਾਉਣਾ"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ਬੈਟਰੀ ਸੇਵਰ"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ਬੈਟਰੀ ਸੇਵਰ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ਫ਼ੋਨ ਲੋੜੀਂਦਾ ਚਾਰਜ ਹੈ। ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਹੁਣ ਪ੍ਰਤਿਬੰਧਿਤ ਨਹੀਂ ਹਨ।"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ਕੰਮ ਸੰਬੰਧੀ 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"ਜਾਂਚ"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"ਭਾਈਚਾਰਕ"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ਕਲੋਨ"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ਭਾਈਚਾਰਕ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ਲੁਕੀ ਹੋਈ ਸੰਵੇਦਨਸ਼ੀਲ ਸੂਚਨਾ ਸਮੱਗਰੀ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ਐਪ ਸਮੱਗਰੀ ਨੂੰ ਸੁਰੱਖਿਆ ਲਈ ਸਕ੍ਰੀਨ ਸਾਂਝਾਕਰਨ ਤੋਂ ਲੁਕਾਇਆ ਗਿਆ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 9bdea974b51e..d5c8d763bf0e 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2146,10 +2146,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Powiadomienie z informacją o trybie rutynowym"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Oszczędzanie baterii jest włączone"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Ograniczam wykorzystanie baterii, aby przedłużyć jej żywotność"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Oszczędzanie baterii jest włączone"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Oszczędzanie baterii jest włączone, aby wydłużyć jej żywotność"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Oszczędzanie baterii"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Oszczędzanie baterii zostało wyłączone"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon jest wystarczająco naładowany. Funkcje nie są już ograniczone."</string>
@@ -2405,14 +2403,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Służbowy 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Testowy"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Wspólny"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil służbowy"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Przestrzeń prywatna"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wspólny"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Treść poufnego powiadomienia została ukryta"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ze względów bezpieczeństwa zawartość aplikacji jest niewidoczna podczas udostępniania ekranu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bef0713a0f2b..4d9e208233a8 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Economia de bateria ativada"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reduzindo o uso da bateria para prolongar a duração dela"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"A Economia de bateria está ativada"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"A Economia de bateria está ativada para prolongar a duração da carga"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Economia de bateria"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"\"Economia de bateria\" desativada"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Não há carga suficiente no smartphone. Os recursos não estão mais restritos."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Público"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabalho"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6afe44dce413..2074d1e85868 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informações do Modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Poupança de bateria ativada"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reduzir a utilização da bateria para prolongar a autonomia da mesma"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Poupança de bateria ativada"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"A Poupança de bateria está ativada para prolongar a autonomia da bateria"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Poupança de bateria"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"A Poupança de bateria está desativada"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"O telemóvel tem carga suficiente. As funcionalidades já não estão restritas."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Comum"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabalho"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comum"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo das notificações sensíveis ocultado"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo da app ocultado da partilha de ecrã por motivos de segurança"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bef0713a0f2b..4d9e208233a8 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Economia de bateria ativada"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reduzindo o uso da bateria para prolongar a duração dela"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"A Economia de bateria está ativada"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"A Economia de bateria está ativada para prolongar a duração da carga"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Economia de bateria"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"\"Economia de bateria\" desativada"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Não há carga suficiente no smartphone. Os recursos não estão mais restritos."</string>
@@ -2404,14 +2402,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Público"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Perfil de trabalho"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6e6016d87a52..10aa0207bf85 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificare pentru informații despre modul Rutină"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Economisirea bateriei este activată"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Se reduce utilizarea bateriei pentru a-i extinde autonomia"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Economisirea bateriei este activată"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Economisirea bateriei este activată pentru a extinde autonomia"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Economisirea bateriei"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Economisirea bateriei a fost dezactivată"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonul este încărcat suficient. Funcțiile nu mai sunt limitate."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index dbe23ed8dfbc..ff0d1b8818ca 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2146,10 +2146,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Уведомление о батарее"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Включен режим энергосбережения"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Экономия заряда продлит время работы от батареи."</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Включен режим энергосбережения"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Это нужно, чтобы продлить время работы от батареи."</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Режим энергосбережения"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Режим энергосбережения отключен"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Телефон заряжен достаточно. Функции больше не ограничены."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 080043cc32d9..18b26f27816b 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"දිනචරියා ප්‍රකාර තතු දැනුම්දීම"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"බැටරි සුරැකුම ක්‍රියාත්මකයි"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"බැටරි ආයු කාලය දිගු කිරීම සඳහා බැටරි භාවිතය අඩු කිරීම"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"බැටරි සුරැකුම ක්‍රියාත්මකයි"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"බැටරි ආයු කාලය දීර්ඝ කිරීමට බැටරි සුරැකුම ක්‍රියාත්මක කර ඇත"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"බැටරි සුරැකුම"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"බැටරි සුරැකුම ක්‍රියාවිරහිත කර ඇත"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"දුරකථනයට ප්‍රමාණවත් ආරෝපණයක් තිබේ. විශේෂාංග තවදුරටත් සීමා කර නැත."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"කාර්යාලය 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"පරීක්ෂණය"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"වාර්ගික"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"කාර්යාල පැතිකඩ"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"රහසිගත අවකාශය"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ක්ලෝන කරන්න"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"වාර්ගික"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"සංවේදී දැනුම්දීම් අන්තර්ගතය සැඟවී ඇත"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ආරක්ෂාව සඳහා යෙදුම් අන්තර්ගතය තිරය බෙදා ගැනීමෙන් සඟවා ඇත"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d88d4f20eec5..3b144d27905f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2146,10 +2146,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upozornenie s informáciami o rutinnom režime"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Bol zapnutý šetrič batérie"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Zníženie spotreby batérie predlžuje jej výdrž"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Šetrič batérie je zapnutý"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Šetrič batérie ja zapnutý, aby sa predĺžila výdrž batérie"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Šetrič batérie"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Šetrič batérie bol vypnutý."</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefón je dostatočne nabitý. Funkcie už nie sú obmedzené."</string>
@@ -2405,14 +2403,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"3. pracovný"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Testovací"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Spoločný"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Pracovný profil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Súkromný priestor"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Spoločný"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivého upozornenia je skrytý"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikácie bol na účely zabezpečenia skrytý v zdieľaní obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 73aa2e41d270..1b7a2a145f80 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2146,10 +2146,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutinsko informativno obvestilo o načinu delovanja"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Varčevanje z energijo baterije je vklopljeno"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Manjša poraba energije baterije za podaljšanje časa delovanja baterije"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Varčevanje z energijo baterije je vklopljeno"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Varčevanje z energijo baterije je vklopljeno za podaljšanje časa delovanja pri baterijskem napajanju"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Varčevanje z energijo baterije"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Varčevanje z energijo baterije je izklopljeno"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterija v telefonu je dovolj napolnjena. Funkcije niso več omejene."</string>
@@ -2405,14 +2403,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Delo 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Preizkus"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Skupno"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Delovni profil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Zasebni prostor"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Skupno"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Občutljiva vsebina obvestila je bila skrita"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Pri deljenju zaslona je vsebina aplikacije skrita zaradi varnosti"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index ac826a48dc8e..87d10860a0b0 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2145,10 +2145,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Обавештење о информацијама Рутинског режима"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Уштеда батерије је укључена"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Смањује се потрошња батерије да би се продужило њено трајање"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Уштеда батерије је укључена"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Уштеда батерије је укључена да би се продужило трајање батерије"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Уштеда батерије"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Уштеда батерије је искључена"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Батерија телефона је довољно напуњена. Функције више нису ограничене."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 1f0b65c76acb..3ca5c9fcb4ab 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Avisering om rutinläge"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Batterisparläget har aktiverats"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Minskar batteriförbrukning för att förlänga batteritiden"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Batterisparläget är aktiverat"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Batterisparläget är aktiverat för att förlänga batteritiden"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterisparläge"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterisparläget har inaktiverats"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonen har laddats tillräckligt. Funktioner begränsas inte längre."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Arbete 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Allmän"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Jobbprofil"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Allmän"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Känsligt aviseringsinnehåll dolt"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av säkerhetsskäl döljs appinnehållet vid skärmdelning"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1dc75dd890d9..2efca2b4a891 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Arifa ya maelezo ya Hali ya Kawaida"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Kiokoa Betri kimewashwa"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Inapunguza matumizi ya betri ili kuongeza muda wa matumizi ya betri"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Kiokoa Betri kimewashwa"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Kiokoa Betri kimewashwa ili kuongeza muda wa matumizi ya betri"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Kiokoa betri"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Kiokoa Betri kimezimwa"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Simu ina chaji ya kutosha. Vipengele havizuiliwi tena."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Wa 3 wa Kazini"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Jaribio"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Unaoshirikiwa"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Wasifu wa kazini"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Sehemu ya faragha"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nakala"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wasifu wa pamoja"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Maudhui nyeti kwenye arifa yamefichwa"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Maudhui ya programu yamefichwa ili yasionekane kwenye skrini ya pamoja kwa sababu za kiusalama"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index c11b9c246aa8..0c704e353836 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"வழக்கமான பேட்டரி சேமிப்பானுக்கான விவர அறிவிப்பு"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"பேட்டரி சேமிப்பு இயக்கப்பட்டுள்ளது"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"பேட்டரி ஆயுளை நீட்டிக்க, பேட்டரி உபயோகத்தைக் குறைக்கிறது"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"பேட்டரி ஆயுளை நீட்டிக்க பேட்டரி சேமிப்பான் இயக்கப்பட்டது"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"பேட்டரி சேமிப்பு"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"பேட்டரி சேமிப்பான் ஆஃப் செய்யப்பட்டுள்ளது"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"மொபைலில் போதுமான சார்ஜ் உள்ளது. அம்சங்கள் இனி தடையின்றி இயங்கும்."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"பணி 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"பரிசோதனை"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"பொது"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"பணிக் கணக்கு"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ரகசிய இடம்"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"குளோன்"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"பொது"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"உணர்வுபூர்வமான அறிவிப்பு உள்ளடக்கம் மறைக்கப்பட்டது"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"பாதுகாப்பிற்காக, திரைப் பகிர்வில் இருந்து ஆப்ஸ் உள்ளடக்கம் மறைக்கப்பட்டுள்ளது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 4f27ba4e5b36..b465000e9690 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"బ్యాటరీ సేవర్ ఆన్ చేయబడింది"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"బ్యాటరీ జీవితకాలాన్ని పొడిగించడానికి బ్యాటరీ వినియోగాన్ని తగ్గించడం"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"బ్యాటరీ సేవర్ ఆన్‌లో ఉంది"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"బ్యాటరీ లైఫ్‌ను పొడిగించడానికి బ్యాటరీ సేవర్ ఆన్ చేయబడింది"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"బ్యాటరీ సేవర్"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"బ్యాటరీ సేవర్ ఆఫ్ చేయబడింది"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ఫోన్‌కు తగినంత ఛార్జింగ్ ఉంది. ఫీచర్‌లు ఇప్పటి నుండి పరిమితం చేయబడవు."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ఆఫీస్ 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"పరీక్ష"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"కమ్యూనల్"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"వర్క్ ప్రొఫైల్"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"ప్రైవేట్ స్పేస్"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"క్లోన్"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"కమ్యూనల్"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"గోప్యమైన నోటిఫికేషన్ కంటెంట్ దాచబడింది"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"సెక్యూరిటీ కోసం స్క్రీన్ షేర్ నుండి యాప్ కంటెంట్ దాచబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3e773e024ad4..535396de7936 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"การแจ้งเตือนข้อมูลโหมดกิจวัตร"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"เปิดโหมดประหยัดแบตเตอรี่แล้ว"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ลดการใช้งานแบตเตอรี่เพื่อยืดอายุการใช้งานแบตเตอรี่"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"โหมดประหยัดแบตเตอรี่เปิดอยู่"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"เปิดโหมดประหยัดแบตเตอรี่แล้วเพื่อยืดระยะเวลาการใช้งานแบตเตอรี่"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"โหมดประหยัดแบตเตอรี่"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ปิดโหมดประหยัดแบตเตอรี่แล้ว"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"โทรศัพท์มีแบตเตอรี่เพียงพอ ไม่มีการจำกัดฟีเจอร์แล้ว"</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"งาน 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"ทดสอบ"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"ส่วนกลาง"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"โปรไฟล์งาน"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"พื้นที่ส่วนตัว"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"โคลน"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ส่วนกลาง"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"เนื้อหาการแจ้งเตือนที่ละเอียดอ่อนซ่อนอยู่"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ซ่อนเนื้อหาแอปจากการแชร์หน้าจอเพื่อความปลอดภัย"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e04b09a100ed..6eab396ca97c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification ng impormasyon ng Routine Mode"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Na-on ang Pantipid ng Baterya"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Binabawasan ang paggamit sa baterya para mapatagal ang baterya"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Naka-on ang Pantipid ng Baterya"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Naka-on ang Pantipid ng Baterya para mapahaba ang tagal ng baterya"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pantipid ng Baterya"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Na-off ang Pantipid ng Baterya"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"May sapat na charge ang telepono. Hindi na pinaghihigpitan ang mga feature."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8c9c6d85a65f..4c8083a754a5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutin Modu bilgi bildirimi"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Pil Tasarrufu açıldı"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Pil ömrünü uzatmak için pil kullanımını azaltma"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Pil Tasarrufu açık"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Pil ömrünü uzatmak için Pil Tasarrufu özelliği açıldı"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pil Tasarrufu"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Pil Tasarrufu kapatıldı"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon yeterince şarj oldu. Özellikler artık kısıtlanmış değil."</string>
@@ -2403,14 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Paylaşılan"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"İş profili"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Özel alan"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Paylaşılan"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Hassas bildirim içerikleri gizlendi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Uygulama içerikleri, güvenlik nedeniyle ekran paylaşımında gizlendi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 88a661683b8d..6f94a2cf4e51 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2405,14 +2405,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"Робочий профіль 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Тестовий профіль"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Спільний профіль"</string>
- <!-- no translation found for accessibility_label_managed_profile (3366526886209832641) -->
- <skip />
- <!-- no translation found for accessibility_label_private_profile (1436459319135548969) -->
- <skip />
- <!-- no translation found for accessibility_label_clone_profile (7579118375042398784) -->
- <skip />
- <!-- no translation found for accessibility_label_communal_profile (1437173163111334791) -->
- <skip />
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Робочий профіль"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватний простір"</string>
+ <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Копія профілю"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Спільний профіль"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Чутливий вміст сповіщення приховано"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"З міркувань безпеки вміст додатка приховано під час показу екрана"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 1f0bb9b00ee8..ed1a358d19a8 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"روٹین موڈ معلومات کی اطلاع"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"بیٹری سیور کو آن کیا گیا"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"بیٹری لائف کو بڑھانے کے لیے بیٹری کے استعمال کو کم کیا جا رہا ہے"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"بیٹری سیور آن ہے"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"بیٹری لائف کو بڑھانے کے لیے بیٹری سیور کو آن کر دیا گیا ہے"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"بیٹری سیور"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"بیٹری سیور کو آف کر دیا گیا"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"فون میں کافی چارج ہے۔ خصوصیات پر اب پابندی نہیں ہے۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 21afbefa4f57..4ddd368766c8 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Kun tartibi rejimi haqidagi bildirishnoma"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Quvvat tejalishi yoqildi"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Batareya tejalganda batareya quvvati uzoqroq vaqtga yetadi"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Quvvat tejash rejimi yoniq"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Batareya quvvatini uzaytirish uchun Quvvat tejash yoqilgan"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Quvvat tejash"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Quvvat tejash rejimi faolsizlantirildi"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon yetarli quvvatlandi. Funksiyalar endi cheklovlarsiz ishlaydi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index d7d81d142253..c633c2af0a15 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Thông báo cung cấp thông tin về chế độ sạc thông thường"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Đã bật Trình tiết kiệm pin"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Giảm mức sử dụng pin để kéo dài thời lượng pin"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Trình tiết kiệm pin đang bật"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Trình tiết kiệm pin được bật để kéo dài thời lượng pin"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Trình tiết kiệm pin"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Trình tiết kiệm pin đã tắt"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Điện thoại còn đủ pin. Các tính năng không bị hạn chế nữa."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 2ee3d39e500a..f16881a847c3 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式信息通知"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"省电模式已开启"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"降低电池用量以延长电池续航时间"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"省电模式已开启"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"已开启省电模式以延长电池续航时间"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"省电模式"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"省电模式已关闭"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"手机电量充足。各项功能不再受限。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 682afea97cf6..efa260f3f4e6 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"「日常安排模式」資料通知"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"已開啟「慳電模式」"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"減少用電可延長電池壽命"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"「慳電模式」已開啟"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"已開啟「慳電模式」,以延長電池壽命"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"慳電模式"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"已關閉慳電模式"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"手機電量充足。各項功能已不再受限。"</string>
@@ -2403,10 +2401,10 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"測試"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>
- <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"工作資料夾"</string>
+ <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"工作設定檔"</string>
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
- <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共通"</string>
+ <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"已隱藏敏感通知內容"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,應用程式內容已從分享螢幕畫面隱藏"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c99a12e57185..7dc3fd63719e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2144,10 +2144,8 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Isaziso solwazi lwe-Routine Mode"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Isilondolozi Sebhethri sivuliwe"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Ukwehlisa ukusetshenziswa kwebhethri ukuze kunwetshiswe impilo yebhethri"</string>
- <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) -->
- <skip />
- <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) -->
- <skip />
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Isilondolozi sebhethri sivuliwe"</string>
+ <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Isilondolozi Sebhethri sivuliwe ukuze kunwetshwe impilo yebhethri"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Isilondolozi sebhethri"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Isilondolozi sebhethri sivaliwe"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Ifoni inokushajwa okwanele. Izici azisakhawulelwe."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 877d11e0a09a..edaf8b568c70 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6093,6 +6093,18 @@
<!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. -->
<bool name="config_letterboxIsEducationEnabled">false</bool>
+ <!-- The width in dp to use to detect vertical thin letterboxing.
+ If W is the available width and w is the letterbox width, an app
+ is thin letterboxed if the value here is < (W - w) / 2
+ If the value is < 0 the thin letterboxing policy is disabled -->
+ <dimen name="config_letterboxThinLetterboxWidthDp">-1dp</dimen>
+
+ <!-- The height in dp to use to detect horizontal thin letterboxing
+ If H is the available height and h is the letterbox height, an app
+ is thin letterboxed if the value here is < (H - h) / 2
+ If the value is < 0 the thin letterboxing policy is disabled -->
+ <dimen name="config_letterboxThinLetterboxHeightDp">-1dp</dimen>
+
<!-- Default min aspect ratio for unresizable apps which are eligible for size compat mode.
Values <= 1.0 will be ignored. Activity min/max aspect ratio restrictions will still be
espected so this override can control the maximum screen area that can be occupied by
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1fca4f859294..59e4161b2e0b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -6484,4 +6484,23 @@ ul.</string>
<string name="satellite_notification_how_it_works">How it works</string>
<!-- Initial/System provided label shown for an app which gets unarchived. [CHAR LIMIT=64]. -->
<string name="unarchival_session_app_label">Pending...</string>
+
+ <!-- Fingerprint dangling notification title -->
+ <string name="fingerprint_dangling_notification_title">Set up Fingerprint Unlock again</string>
+ <!-- Fingerprint dangling notification content for only 1 fingerprint deleted -->
+ <string name="fingerprint_dangling_notification_msg_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted to improve performance</string>
+ <!-- Fingerprint dangling notification content for more than 1 fingerprints deleted -->
+ <string name="fingerprint_dangling_notification_msg_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted to improve performance</string>
+ <!-- Fingerprint dangling notification content for only 1 fingerprint deleted and no fingerprint left-->
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint.</string>
+ <!-- Fingerprint dangling notification content for more than 1 fingerprints deleted and no fingerprint left -->
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint.</string>
+ <!-- Face dangling notification title -->
+ <string name="face_dangling_notification_title">Set up Face Unlock again</string>
+ <!-- Face dangling notification content -->
+ <string name="face_dangling_notification_msg">Your face model wasn\'t working well and was deleted. Set it up again to unlock your phone with face.</string>
+ <!-- Biometric dangling notification "set up" action button -->
+ <string name="biometric_dangling_notification_action_set_up">Set up</string>
+ <!-- Biometric dangling notification "Not now" action button -->
+ <string name="biometric_dangling_notification_action_not_now">Not now</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 54dbc48c99fb..d058fb188d16 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4717,6 +4717,8 @@
<java-symbol type="integer" name="config_letterboxDefaultPositionForTabletopModeReachability" />
<java-symbol type="bool" name="config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled" />
<java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
+ <java-symbol type="dimen" name="config_letterboxThinLetterboxWidthDp" />
+ <java-symbol type="dimen" name="config_letterboxThinLetterboxHeightDp" />
<java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" />
<java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" />
<java-symbol type="bool" name="config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled" />
@@ -5430,4 +5432,15 @@
<!-- For PowerManagerService to determine whether to use auto-suspend mode -->
<java-symbol type="bool" name="config_useAutoSuspend" />
+
+ <!-- Biometric dangling notification strings -->
+ <java-symbol type="string" name="fingerprint_dangling_notification_title" />
+ <java-symbol type="string" name="fingerprint_dangling_notification_msg_1" />
+ <java-symbol type="string" name="fingerprint_dangling_notification_msg_2" />
+ <java-symbol type="string" name="fingerprint_dangling_notification_msg_all_deleted_1" />
+ <java-symbol type="string" name="fingerprint_dangling_notification_msg_all_deleted_2" />
+ <java-symbol type="string" name="face_dangling_notification_title" />
+ <java-symbol type="string" name="face_dangling_notification_msg" />
+ <java-symbol type="string" name="biometric_dangling_notification_action_set_up" />
+ <java-symbol type="string" name="biometric_dangling_notification_action_not_now" />
</resources>
diff --git a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
index c00ebe487620..57bbb1cc9b57 100644
--- a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
+++ b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
@@ -241,6 +241,23 @@ public class ImeBackAnimationControllerTest {
});
}
+ @Test
+ public void testOnBackInvokedHidesImeEvenIfInsetsControlCancelled() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // start back gesture
+ WindowInsetsAnimationControlListener animationControlListener = startBackGesture();
+
+ // simulate ImeBackAnimationController not receiving control (e.g. due to split screen)
+ animationControlListener.onCancelled(mWindowInsetsAnimationController);
+
+ // commit back gesture
+ mBackAnimationController.onBackInvoked();
+
+ // verify that InsetsController#hide is called
+ verify(mInsetsController, times(1)).hide(ime());
+ });
+ }
+
private WindowInsetsAnimationControlListener startBackGesture() {
// start back gesture
mBackAnimationController.onBackStarted(new BackEvent(0f, 0f, 0f, EDGE_LEFT));
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index 72f11198c6c0..0b1b40c8ba8b 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -17,6 +17,7 @@
package android.view;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
+import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
@@ -584,6 +585,44 @@ public class ViewFrameRateTest {
assertEquals(0f, mViewRoot.getLastPreferredFrameRate(), 0f);
}
+ @Test
+ @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
+ FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
+ })
+ public void testQuickTouchBoost() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_LOW);
+ ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ mMovingView.setLayoutParams(layoutParams);
+ mMovingView.setOnClickListener((v) -> {});
+ });
+ waitForFrameRateCategoryToSettle();
+ mActivityRule.runOnUiThread(() -> assertEquals(FRAME_RATE_CATEGORY_LOW,
+ mViewRoot.getLastPreferredFrameRateCategory()));
+ int[] position = new int[2];
+ mActivityRule.runOnUiThread(() -> {
+ mMovingView.getLocationOnScreen(position);
+ position[0] += mMovingView.getWidth() / 2;
+ position[1] += mMovingView.getHeight() / 2;
+ });
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+
+ long now = SystemClock.uptimeMillis();
+ MotionEvent down = MotionEvent.obtain(
+ now, // downTime
+ now, // eventTime
+ MotionEvent.ACTION_DOWN, // action
+ position[0], // x
+ position[1], // y
+ 0 // metaState
+ );
+ down.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+ instrumentation.sendPointerSync(down);
+ assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT, mViewRoot.getLastPreferredFrameRateCategory());
+ }
+
private void runAfterDraw(@NonNull Runnable runnable) {
Handler handler = new Handler(Looper.getMainLooper());
mAfterDrawLatch = new CountDownLatch(1);
@@ -615,7 +654,6 @@ public class ViewFrameRateTest {
for (int i = 0; i < 5 || mViewRoot.getIsFrameRateBoosting(); i++) {
final CountDownLatch drawLatch = new CountDownLatch(1);
- // Now that it is small, any invalidation should have a normal category
ViewTreeObserver.OnDrawListener listener = drawLatch::countDown;
mActivityRule.runOnUiThread(() -> {
@@ -627,5 +665,12 @@ public class ViewFrameRateTest {
mActivityRule.runOnUiThread(
() -> mMovingView.getViewTreeObserver().removeOnDrawListener(listener));
}
+ // after boosting is complete, wait for one more draw cycle to ensure the boost isn't
+ // the last frame rate set
+ mActivityRule.runOnUiThread(() -> {
+ mMovingView.invalidate();
+ runAfterDraw(() -> {});
+ });
+ waitForAfterDraw();
}
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 0b0fd66f0744..b5c264c4ae5e 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -21,7 +21,9 @@ import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.IBrailleDisplayController;
import android.accessibilityservice.MagnificationConfig;
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
+import android.annotation.RequiresNoPermission;
import android.content.pm.ParceledListSlice;
import android.graphics.Region;
import android.hardware.usb.UsbDevice;
@@ -216,16 +218,19 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
public void setAnimationScale(float scale) {}
+ @RequiresNoPermission
@Override
public void setInstalledAndEnabledServices(List<AccessibilityServiceInfo> infos)
throws RemoteException {
}
+ @RequiresNoPermission
@Override
public List<AccessibilityServiceInfo> getInstalledAndEnabledServices() throws RemoteException {
return null;
}
+ @RequiresNoPermission
@Override
public void attachAccessibilityOverlayToDisplay(
int interactionId,
@@ -233,6 +238,7 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
SurfaceControl sc,
IAccessibilityInteractionConnectionCallback callback) {}
+ @RequiresNoPermission
@Override
public void attachAccessibilityOverlayToWindow(
int interactionId,
@@ -240,14 +246,21 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
SurfaceControl sc,
IAccessibilityInteractionConnectionCallback callback) {}
+ @EnforcePermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@Override
- public void connectBluetoothBrailleDisplay(String bluetoothAddress,
- IBrailleDisplayController controller) {}
+ public void connectBluetoothBrailleDisplay(
+ String bluetoothAddress, IBrailleDisplayController controller) {
+ connectBluetoothBrailleDisplay_enforcePermission();
+ }
+ @RequiresNoPermission
@Override
- public void connectUsbBrailleDisplay(UsbDevice usbDevice,
- IBrailleDisplayController controller) {}
+ public void connectUsbBrailleDisplay(
+ UsbDevice usbDevice, IBrailleDisplayController controller) {}
+ @EnforcePermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)
@Override
- public void setTestBrailleDisplayData(List<Bundle> brailleDisplays) {}
+ public void setTestBrailleDisplayData(List<Bundle> brailleDisplays) {
+ setTestBrailleDisplayData_enforcePermission();
+ }
}
diff --git a/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
index 1d91af57ca56..991ada89c51e 100644
--- a/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
+++ b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
@@ -328,8 +328,11 @@ public class PackageMonitorTest {
verify(spyPackageMonitor, times(1)).onBeginPackageChanges();
verify(spyPackageMonitor, times(1))
.onPackageUpdateStarted(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID));
-
ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(spyPackageMonitor, times(1))
+ .onPackageUpdateStartedWithExtras(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID),
+ argumentCaptor.capture());
+
verify(spyPackageMonitor, times(1)).onPackageDisappearedWithExtras(eq(FAKE_PACKAGE_NAME),
argumentCaptor.capture());
Bundle capturedExtras = argumentCaptor.getValue();
@@ -362,11 +365,16 @@ public class PackageMonitorTest {
spyPackageMonitor.doHandlePackageEvent(intent);
verify(spyPackageMonitor, times(1)).onBeginPackageChanges();
+ ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(spyPackageMonitor, times(1))
.onPackageUpdateStarted(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID));
+ verify(spyPackageMonitor, times(1))
+ .onPackageUpdateStartedWithExtras(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID),
+ argumentCaptor.capture());
verify(spyPackageMonitor, times(1)).onPackageModified(eq(FAKE_PACKAGE_NAME));
+ verify(spyPackageMonitor, times(1)).onPackageModifiedWithExtras(eq(FAKE_PACKAGE_NAME),
+ argumentCaptor.capture());
- ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(spyPackageMonitor, times(1))
.onPackageDisappearedWithExtras(eq(FAKE_PACKAGE_NAME), argumentCaptor.capture());
Bundle capturedExtras = argumentCaptor.getValue();
@@ -399,12 +407,18 @@ public class PackageMonitorTest {
spyPackageMonitor.doHandlePackageEvent(intent);
verify(spyPackageMonitor, times(1)).onBeginPackageChanges();
+ ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(spyPackageMonitor, times(1))
.onPackageRemoved(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID));
verify(spyPackageMonitor, times(1))
+ .onPackageRemovedWithExtras(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID),
+ argumentCaptor.capture());
+ verify(spyPackageMonitor, times(1))
.onPackageRemovedAllUsers(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID));
+ verify(spyPackageMonitor, times(1))
+ .onPackageRemovedAllUsersWithExtras(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID),
+ argumentCaptor.capture());
- ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(spyPackageMonitor, times(1)).onPackageDisappearedWithExtras(eq(FAKE_PACKAGE_NAME),
argumentCaptor.capture());
Bundle capturedExtras = argumentCaptor.getValue();
@@ -436,11 +450,16 @@ public class PackageMonitorTest {
spyPackageMonitor.doHandlePackageEvent(intent);
verify(spyPackageMonitor, times(1)).onBeginPackageChanges();
+ ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(spyPackageMonitor, times(1))
.onPackageUpdateFinished(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID));
+ verify(spyPackageMonitor, times(1))
+ .onPackageModifiedWithExtras(eq(FAKE_PACKAGE_NAME), argumentCaptor.capture());
verify(spyPackageMonitor, times(1)).onPackageModified(eq(FAKE_PACKAGE_NAME));
+ verify(spyPackageMonitor, times(1))
+ .onPackageModifiedWithExtras(eq(FAKE_PACKAGE_NAME), argumentCaptor.capture());
+
- ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(spyPackageMonitor, times(1)).onPackageAppearedWithExtras(eq(FAKE_PACKAGE_NAME),
argumentCaptor.capture());
Bundle capturedExtras = argumentCaptor.getValue();
@@ -472,8 +491,11 @@ public class PackageMonitorTest {
verify(spyPackageMonitor, times(1)).onBeginPackageChanges();
verify(spyPackageMonitor, times(1))
.onPackageAdded(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID));
-
ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(spyPackageMonitor, times(1))
+ .onPackageAddedWithExtras(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID),
+ argumentCaptor.capture());
+
verify(spyPackageMonitor, times(1)).onPackageAppearedWithExtras(eq(FAKE_PACKAGE_NAME),
argumentCaptor.capture());
Bundle capturedExtras = argumentCaptor.getValue();
diff --git a/data/keyboards/Android.bp b/data/keyboards/Android.bp
index e62678f92d8b..423b55bd85db 100644
--- a/data/keyboards/Android.bp
+++ b/data/keyboards/Android.bp
@@ -33,7 +33,7 @@ prebuilt_usr_keylayout {
srcs: [
"*.kl",
],
- installable: false,
+ no_full_install: true,
}
prebuilt_usr_keychars {
@@ -41,7 +41,7 @@ prebuilt_usr_keychars {
srcs: [
"*.kcm",
],
- installable: false,
+ no_full_install: true,
}
prebuilt_usr_idc {
@@ -49,5 +49,5 @@ prebuilt_usr_idc {
srcs: [
"*.idc",
],
- installable: false,
+ no_full_install: true,
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 59092d48bcaa..14388a6d42ff 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -28,6 +28,7 @@ import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CLOSE;
+import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_DRAG_RESIZE;
import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN;
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
@@ -850,6 +851,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
Log.e(TAG, "onTaskFragmentParentInfoChanged on empty Task id=" + taskId);
return;
}
+
+ if (!parentInfo.isVisible()) {
+ // Only making the TaskContainer invisible and drops the other info, and perform the
+ // update when the next time the Task becomes visible.
+ taskContainer.setIsVisible(false);
+ return;
+ }
+
// Checks if container should be updated before apply new parentInfo.
final boolean shouldUpdateContainer = taskContainer.shouldUpdateContainer(parentInfo);
taskContainer.updateTaskFragmentParentInfo(parentInfo);
@@ -3243,6 +3252,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
synchronized (mLock) {
final TransactionRecord transactionRecord =
mTransactionManager.startNewTransaction();
+ transactionRecord.setOriginType(TASK_FRAGMENT_TRANSIT_DRAG_RESIZE);
final WindowContainerTransaction wct = transactionRecord.getTransaction();
final TaskContainer taskContainer = mTaskContainers.get(taskId);
if (taskContainer != null) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 67d34c71b4d6..a68373832a14 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -151,6 +151,10 @@ class TaskContainer {
return mIsVisible;
}
+ void setIsVisible(boolean visible) {
+ mIsVisible = visible;
+ }
+
boolean hasDirectActivity() {
return mHasDirectActivity;
}
@@ -185,13 +189,15 @@ class TaskContainer {
boolean shouldUpdateContainer(@NonNull TaskFragmentParentInfo info) {
final Configuration configuration = info.getConfiguration();
- return info.isVisible()
- // No need to update presentation in PIP until the Task exit PIP.
- && !isInPictureInPicture(configuration)
- // If the task properties equals regardless of starting position, don't need to
- // update the container.
- && (mConfiguration.diffPublicOnly(configuration) != 0
- || mDisplayId != info.getDisplayId());
+ if (isInPictureInPicture(configuration)) {
+ // No need to update presentation in PIP until the Task exit PIP.
+ return false;
+ }
+
+ // If the task properties equals regardless of starting position, don't
+ // need to update the container.
+ return mConfiguration.diffPublicOnly(configuration) != 0
+ || mDisplayId != info.getDisplayId();
}
/**
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index fab298d6d58b..049a9e2c2aca 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -580,7 +580,7 @@ public class OverlayPresentationTest {
final TaskContainer.TaskProperties taskProperties = taskContainer.getTaskProperties();
final TaskFragmentParentInfo parentInfo = new TaskFragmentParentInfo(
new Configuration(taskProperties.getConfiguration()), taskProperties.getDisplayId(),
- false /* visible */, false /* hasDirectActivity */, null /* decorSurface */);
+ true /* visible */, false /* hasDirectActivity */, null /* decorSurface */);
mSplitController.onTaskFragmentParentInfoChanged(mTransaction, TASK_ID, parentInfo);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index a52587778fa8..7d86ec2272af 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -1619,6 +1619,48 @@ public class SplitControllerTest {
verify(mEmbeddedActivityWindowInfoCallback, never()).accept(any());
}
+ @Test
+ public void testTaskFragmentParentInfoChanged() {
+ // Making a split
+ final Activity secondaryActivity = createMockActivity();
+ addSplitTaskFragments(mActivity, secondaryActivity, false /* clearTop */);
+
+ // Updates the parent info.
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+ final Configuration configuration = new Configuration();
+ final TaskFragmentParentInfo originalInfo = new TaskFragmentParentInfo(configuration,
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */,
+ null /* decorSurface */);
+ mSplitController.onTaskFragmentParentInfoChanged(mock(WindowContainerTransaction.class),
+ TASK_ID, originalInfo);
+ assertTrue(taskContainer.isVisible());
+
+ // Making a public configuration change while the Task is invisible.
+ configuration.densityDpi += 100;
+ final TaskFragmentParentInfo invisibleInfo = new TaskFragmentParentInfo(configuration,
+ DEFAULT_DISPLAY, false /* visible */, false /* hasDirectActivity */,
+ null /* decorSurface */);
+ mSplitController.onTaskFragmentParentInfoChanged(mock(WindowContainerTransaction.class),
+ TASK_ID, invisibleInfo);
+
+ // Ensure the TaskContainer is inivisible, but the configuration is not updated.
+ assertFalse(taskContainer.isVisible());
+ assertTrue(taskContainer.getTaskFragmentParentInfo().getConfiguration().diffPublicOnly(
+ configuration) > 0);
+
+ // Updates when Task to become visible
+ final TaskFragmentParentInfo visibleInfo = new TaskFragmentParentInfo(configuration,
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */,
+ null /* decorSurface */);
+ mSplitController.onTaskFragmentParentInfoChanged(mock(WindowContainerTransaction.class),
+ TASK_ID, visibleInfo);
+
+ // Ensure the Task is visible and configuration is updated.
+ assertTrue(taskContainer.isVisible());
+ assertFalse(taskContainer.getTaskFragmentParentInfo().getConfiguration().diffPublicOnly(
+ configuration) > 0);
+ }
+
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
return createMockActivity(TASK_ID);
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 7ff204c695f8..fe68123513ca 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -64,3 +64,10 @@ flag {
description: "Enables long-press action for nav handle when a bubble is expanded"
bug: "324910035"
}
+
+flag {
+ name: "enable_optional_bubble_overflow"
+ namespace: "multitasking"
+ description: "Hides the bubble overflow if there aren't any overflowed bubbles"
+ bug: "334175587"
+}
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index b9ff5c682b42..1c8f5e60c5c9 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -53,7 +53,7 @@
<string name="accessibility_split_top" msgid="2789329702027147146">"Verdeel bo"</string>
<string name="accessibility_split_bottom" msgid="8694551025220868191">"Verdeel onder"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Gebruik eenhandmodus"</string>
- <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Swiep van die onderkant van die skerm af op of tik enige plek bo die program om uit te gaan"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Swiep van die onderkant van die skerm af op of tik enige plek bo die app om uit te gaan"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Begin eenhandmodus"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Verlaat eenhandmodus"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Instellings vir <xliff:g id="APP_NAME">%1$s</xliff:g>-borrels"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 1fde4cfb76f8..3aecf5f53cf0 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -53,7 +53,7 @@
<string name="accessibility_split_top" msgid="2789329702027147146">"Diviser dans la partie supérieure"</string>
<string name="accessibility_split_bottom" msgid="8694551025220868191">"Diviser dans la partie inférieure"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utiliser le mode Une main"</string>
- <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran du bas vers le haut, ou touchez n\'importe où sur l\'écran en haut de l\'application"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran du bas vers le haut, ou touchez n\'importe où sur l\'écran en haut de l\'appli"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Démarrer le mode Une main"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Quitter le mode Une main"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Paramètres pour les bulles de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index e7233ae029b5..4002e4d04d51 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -52,7 +52,7 @@
<string name="accessibility_split_right" msgid="8441001008181296837">"Affichée à droite"</string>
<string name="accessibility_split_top" msgid="2789329702027147146">"Affichée en haut"</string>
<string name="accessibility_split_bottom" msgid="8694551025220868191">"Affichée en haut"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utiliser le mode une main"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utilisation du mode une main"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran de bas en haut ou appuyez n\'importe où au-dessus de l\'application"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Démarrer le mode une main"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Quitter le mode une main"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index fc3942095fdf..27d4cfcf22d5 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -52,7 +52,7 @@
<string name="accessibility_split_right" msgid="8441001008181296837">"Podijeli desno"</string>
<string name="accessibility_split_top" msgid="2789329702027147146">"Podijeli gore"</string>
<string name="accessibility_split_bottom" msgid="8694551025220868191">"Podijeli dolje"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korištenje načina rada jednom rukom"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Upotreba načina rada jednom rukom"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Za izlaz prijeđite prstom od dna zaslona prema gore ili dodirnite bio gdje iznad aplikacije"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pokretanje načina rada jednom rukom"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Izlaz iz načina rada jednom rukom"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index d44033c72302..a426b206b0cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -26,6 +26,7 @@ import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationS
import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
import static com.android.wm.shell.transition.TransitionAnimationHelper.edgeExtendWindow;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE;
import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -190,6 +191,10 @@ class ActivityEmbeddingAnimationRunner {
@NonNull
private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
+ if (info.getType() == TRANSIT_TASK_FRAGMENT_DRAG_RESIZE) {
+ // Jump cut for AE drag resizing because the content is veiled.
+ return new ArrayList<>();
+ }
boolean isChangeTransition = false;
for (TransitionInfo.Change change : info.getChanges()) {
if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
index 1f9358e2aa91..d6b9d34c5ab3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
@@ -22,6 +22,7 @@ import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static com.android.wm.shell.transition.DefaultTransitionHandler.isSupportedOverrideAnimation;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE;
import static java.util.Objects.requireNonNull;
@@ -90,6 +91,12 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
/** Whether ActivityEmbeddingController should animate this transition. */
public boolean shouldAnimate(@NonNull TransitionInfo info) {
+ if (info.getType() == TRANSIT_TASK_FRAGMENT_DRAG_RESIZE) {
+ // The TRANSIT_TASK_FRAGMENT_DRAG_RESIZE type happens when the user drags the
+ // interactive divider to resize the split containers. The content is veiled, so we will
+ // handle the transition with a jump cut.
+ return true;
+ }
boolean containsEmbeddingChange = false;
for (TransitionInfo.Change change : info.getChanges()) {
if (!change.hasFlags(FLAG_FILLS_TASK) && change.hasFlags(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 037397c8e40b..87aac0b55e35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1368,28 +1368,32 @@ public class BubbleController implements ConfigurationChangeListener,
}
String appBubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user);
- Log.i(TAG, "showOrHideAppBubble, key= " + appBubbleKey + " stackVisibility= "
- + (mStackView != null ? mStackView.getVisibility() : " null ")
- + " statusBarShade=" + mIsStatusBarShade);
PackageManager packageManager = getPackageManagerForUser(mContext, user.getIdentifier());
- if (!isResizableActivity(intent, packageManager, appBubbleKey)) return;
+ if (!isResizableActivity(intent, packageManager, appBubbleKey)) return; // logs errors
Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(appBubbleKey);
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "showOrHideAppBubble, key=%s existingAppBubble=%s stackVisibility=%s "
+ + "statusBarShade=%s",
+ appBubbleKey, existingAppBubble,
+ (mStackView != null ? mStackView.getVisibility() : "null"),
+ mIsStatusBarShade);
+
if (existingAppBubble != null) {
BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
if (isStackExpanded()) {
if (selectedBubble != null && appBubbleKey.equals(selectedBubble.getKey())) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "collapseStack for %s", appBubbleKey);
// App bubble is expanded, lets collapse
- Log.i(TAG, " showOrHideAppBubble, selected bubble is app bubble, collapsing");
collapseStack();
} else {
+ ProtoLog.d(WM_SHELL_BUBBLES, "setSelected for %s", appBubbleKey);
// App bubble is not selected, select it
- Log.i(TAG, " showOrHideAppBubble, expanded, selecting existing app bubble");
mBubbleData.setSelectedBubble(existingAppBubble);
}
} else {
+ ProtoLog.d(WM_SHELL_BUBBLES, "setSelectedBubbleAndExpandStack %s", appBubbleKey);
// App bubble is not selected, select it & expand
- Log.i(TAG, " showOrHideAppBubble, expand and select existing app bubble");
mBubbleData.setSelectedBubbleAndExpandStack(existingAppBubble);
}
} else {
@@ -1397,13 +1401,12 @@ public class BubbleController implements ConfigurationChangeListener,
Bubble b = mBubbleData.getOverflowBubbleWithKey(appBubbleKey);
if (b != null) {
// It's in the overflow, so remove it & reinflate
- Log.i(TAG, " showOrHideAppBubble, expanding app bubble from overflow");
mBubbleData.removeOverflowBubble(b);
} else {
// App bubble does not exist, lets add and expand it
- Log.i(TAG, " showOrHideAppBubble, creating and expanding app bubble");
b = Bubble.createAppBubble(intent, user, icon, mMainExecutor);
}
+ ProtoLog.d(WM_SHELL_BUBBLES, "inflateAndAdd %s", appBubbleKey);
b.setShouldAutoExpand(true);
inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index a87116ea4670..607a3b5423d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -185,7 +185,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
nextTarget = snapAlgorithm.getDismissStartTarget();
}
if (nextTarget != null) {
- mSplitLayout.snapToTarget(mSplitLayout.getDividePosition(), nextTarget);
+ mSplitLayout.snapToTarget(mSplitLayout.getDividerPosition(), nextTarget);
return true;
}
return super.performAccessibilityAction(host, action, args);
@@ -345,9 +345,9 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mMoving = true;
}
if (mMoving) {
- final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
+ final int position = mSplitLayout.getDividerPosition() + touchPos - mStartPos;
mLastDraggingPosition = position;
- mSplitLayout.updateDivideBounds(position);
+ mSplitLayout.updateDividerBounds(position);
}
break;
case MotionEvent.ACTION_UP:
@@ -363,7 +363,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
final float velocity = isLeftRightSplit
? mVelocityTracker.getXVelocity()
: mVelocityTracker.getYVelocity();
- final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
+ final int position = mSplitLayout.getDividerPosition() + touchPos - mStartPos;
final DividerSnapAlgorithm.SnapTarget snapTarget =
mSplitLayout.findSnapTarget(position, velocity, false /* hardDismiss */);
mSplitLayout.snapToTarget(position, snapTarget);
@@ -472,12 +472,12 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mInteractive = interactive;
mHideHandle = hideHandle;
if (!mInteractive && mHideHandle && mMoving) {
- final int position = mSplitLayout.getDividePosition();
- mSplitLayout.flingDividePosition(
+ final int position = mSplitLayout.getDividerPosition();
+ mSplitLayout.flingDividerPosition(
mLastDraggingPosition,
position,
mSplitLayout.FLING_RESIZE_DURATION,
- () -> mSplitLayout.setDividePosition(position, true /* applyLayoutChange */));
+ () -> mSplitLayout.setDividerPosition(position, true /* applyLayoutChange */));
mMoving = false;
}
releaseTouching();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 6b2d544c192a..2ea32f44a78b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -78,7 +78,7 @@ import java.util.function.Consumer;
/**
* Records and handles layout of splits. Helps to calculate proper bounds when configuration or
- * divide position changes.
+ * divider position changes.
*/
public final class SplitLayout implements DisplayInsetsController.OnInsetsChangedListener {
private static final String TAG = "SplitLayout";
@@ -278,7 +278,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return mSplitWindowManager == null ? null : mSplitWindowManager.getSurfaceControl();
}
- int getDividePosition() {
+ int getDividerPosition() {
return mDividerPosition;
}
@@ -489,20 +489,20 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void setDividerAtBorder(boolean start) {
final int pos = start ? mDividerSnapAlgorithm.getDismissStartTarget().position
: mDividerSnapAlgorithm.getDismissEndTarget().position;
- setDividePosition(pos, false /* applyLayoutChange */);
+ setDividerPosition(pos, false /* applyLayoutChange */);
}
/**
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
*/
- void updateDivideBounds(int position) {
+ void updateDividerBounds(int position) {
updateBounds(position);
mSplitLayoutHandler.onLayoutSizeChanging(this, mSurfaceEffectPolicy.mParallaxOffset.x,
mSurfaceEffectPolicy.mParallaxOffset.y);
}
- void setDividePosition(int position, boolean applyLayoutChange) {
+ void setDividerPosition(int position, boolean applyLayoutChange) {
mDividerPosition = position;
updateBounds(mDividerPosition);
if (applyLayoutChange) {
@@ -511,14 +511,14 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
/**
- * Updates divide position and split bounds base on the ratio within root bounds. Falls back
+ * Updates divider position and split bounds base on the ratio within root bounds. Falls back
* to middle position if the provided SnapTarget is not supported.
*/
public void setDivideRatio(@PersistentSnapPosition int snapPosition) {
final DividerSnapAlgorithm.SnapTarget snapTarget = mDividerSnapAlgorithm.findSnapTarget(
snapPosition);
- setDividePosition(snapTarget != null
+ setDividerPosition(snapTarget != null
? snapTarget.position
: mDividerSnapAlgorithm.getMiddleTarget().position,
false /* applyLayoutChange */);
@@ -546,24 +546,24 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
/**
- * Sets new divide position and updates bounds correspondingly. Notifies listener if the new
+ * Sets new divider position and updates bounds correspondingly. Notifies listener if the new
* target indicates dismissing split.
*/
public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
switch (snapTarget.snapPosition) {
case SNAP_TO_START_AND_DISMISS:
- flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
+ flingDividerPosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
case SNAP_TO_END_AND_DISMISS:
- flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
+ flingDividerPosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
default:
- flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
- () -> setDividePosition(snapTarget.position, true /* applyLayoutChange */));
+ flingDividerPosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
+ () -> setDividerPosition(snapTarget.position, true /* applyLayoutChange */));
break;
}
}
@@ -615,19 +615,19 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void flingDividerToDismiss(boolean toEnd, int reason) {
final int target = toEnd ? mDividerSnapAlgorithm.getDismissEndTarget().position
: mDividerSnapAlgorithm.getDismissStartTarget().position;
- flingDividePosition(getDividePosition(), target, FLING_EXIT_DURATION,
+ flingDividerPosition(getDividerPosition(), target, FLING_EXIT_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(toEnd, reason));
}
/** Fling divider from current position to center position. */
public void flingDividerToCenter() {
final int pos = mDividerSnapAlgorithm.getMiddleTarget().position;
- flingDividePosition(getDividePosition(), pos, FLING_ENTER_DURATION,
- () -> setDividePosition(pos, true /* applyLayoutChange */));
+ flingDividerPosition(getDividerPosition(), pos, FLING_ENTER_DURATION,
+ () -> setDividerPosition(pos, true /* applyLayoutChange */));
}
@VisibleForTesting
- void flingDividePosition(int from, int to, int duration,
+ void flingDividerPosition(int from, int to, int duration,
@Nullable Runnable flingFinishedCallback) {
if (from == to) {
if (flingFinishedCallback != null) {
@@ -647,7 +647,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
.setDuration(duration);
mDividerFlingAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mDividerFlingAnimator.addUpdateListener(
- animation -> updateDivideBounds((int) animation.getAnimatedValue()));
+ animation -> updateDividerBounds((int) animation.getAnimatedValue()));
mDividerFlingAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
index cf3ad4299cea..713d04bce4e8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
@@ -194,6 +194,10 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi
return mHideSizeCompatRestartButtonTolerance;
}
+ int getDefaultHideRestartButtonTolerance() {
+ return MAX_PERCENTAGE_VAL;
+ }
+
boolean getHasSeenLetterboxEducation(int userId) {
return mLetterboxEduSharedPreferences
.getBoolean(dontShowLetterboxEduKey(userId), /* default= */ false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 4e5c2fa24f25..f195f955692e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -20,11 +20,11 @@ import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+import static android.view.WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.AppCompatTaskInfo;
import android.app.CameraCompatTaskInfo.CameraCompatControlState;
import android.app.TaskInfo;
import android.content.Context;
@@ -219,14 +219,30 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
@VisibleForTesting
boolean shouldShowSizeCompatRestartButton(@NonNull TaskInfo taskInfo) {
- if (!Flags.allowHideScmButton()) {
+ // Always show button if display is phone sized.
+ if (!Flags.allowHideScmButton() || taskInfo.configuration.smallestScreenWidthDp
+ < LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP) {
return true;
}
- final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo;
- final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
- final int letterboxArea = computeArea(appCompatTaskInfo.topActivityLetterboxWidth,
- appCompatTaskInfo.topActivityLetterboxHeight);
- final int taskArea = computeArea(taskBounds.width(), taskBounds.height());
+
+ final int letterboxWidth = taskInfo.appCompatTaskInfo.topActivityLetterboxWidth;
+ final int letterboxHeight = taskInfo.appCompatTaskInfo.topActivityLetterboxHeight;
+ final Rect stableBounds = getTaskStableBounds();
+ final int appWidth = stableBounds.width();
+ final int appHeight = stableBounds.height();
+ // App is floating, should always show restart button.
+ if (appWidth > letterboxWidth && appHeight > letterboxHeight) {
+ return true;
+ }
+ // If app fills the width of the display, don't show restart button (for landscape apps)
+ // if device has a custom tolerance value.
+ if (mHideScmTolerance != mCompatUIConfiguration.getDefaultHideRestartButtonTolerance()
+ && appWidth == letterboxWidth) {
+ return false;
+ }
+
+ final int letterboxArea = letterboxWidth * letterboxHeight;
+ final int taskArea = appWidth * appHeight;
if (letterboxArea == 0 || taskArea == 0) {
return false;
}
@@ -234,13 +250,6 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
return percentageAreaOfLetterboxInTask < mHideScmTolerance;
}
- private int computeArea(int width, int height) {
- if (width == 0 || height == 0) {
- return 0;
- }
- return width * height;
- }
-
private void updateVisibilityOfViews() {
if (mLayout == null) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 17121c8de428..e729c7dd802b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -891,13 +891,13 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
- static Optional<DesktopTasksController> providesDesktopTasksController(
+ static Optional<DesktopTasksController> providesDesktopTasksController(Context context,
@DynamicOverride Optional<Lazy<DesktopTasksController>> desktopTasksController) {
// Use optional-of-lazy for the dependency that this provider relies on.
// Lazy ensures that this provider will not be the cause the dependency is created
// when it will not be returned due to the condition below.
return desktopTasksController.flatMap((lazy)-> {
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(context)) {
return Optional.of(lazy.get());
}
return Optional.empty();
@@ -910,13 +910,13 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
- static Optional<DesktopModeTaskRepository> provideDesktopTaskRepository(
+ static Optional<DesktopModeTaskRepository> provideDesktopTaskRepository(Context context,
@DynamicOverride Optional<Lazy<DesktopModeTaskRepository>> desktopModeTaskRepository) {
// Use optional-of-lazy for the dependency that this provider relies on.
// Lazy ensures that this provider will not be the cause the dependency is created
// when it will not be returned due to the condition below.
return desktopModeTaskRepository.flatMap((lazy)-> {
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(context)) {
return Optional.of(lazy.get());
}
return Optional.empty();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index b574b8159307..a1910c5eb3a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -221,7 +221,7 @@ public abstract class WMShellModule {
Transitions transitions,
Optional<DesktopTasksController> desktopTasksController,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(context)) {
return new DesktopModeWindowDecorViewModel(
context,
mainExecutor,
@@ -278,8 +278,8 @@ public abstract class WMShellModule {
ShellInit init = FreeformComponents.isFreeformEnabled(context)
? shellInit
: null;
- return new FreeformTaskListener(init, shellTaskOrganizer, desktopModeTaskRepository,
- windowDecorViewModel);
+ return new FreeformTaskListener(context, init, shellTaskOrganizer,
+ desktopModeTaskRepository, windowDecorViewModel);
}
@WMSingleton
@@ -535,10 +535,12 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
static Optional<DesktopTasksLimiter> provideDesktopTasksLimiter(
+ Context context,
Transitions transitions,
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
ShellTaskOrganizer shellTaskOrganizer) {
- if (!DesktopModeStatus.isEnabled() || !Flags.enableDesktopWindowingTaskLimit()) {
+ if (!DesktopModeStatus.canEnterDesktopMode(context)
+ || !Flags.enableDesktopWindowingTaskLimit()) {
return Optional.empty();
}
return Optional.of(
@@ -592,23 +594,26 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
static Optional<DesktopTasksTransitionObserver> provideDesktopTasksTransitionObserver(
+ Context context,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
Transitions transitions,
ShellInit shellInit
) {
return desktopModeTaskRepository.flatMap(repository ->
- Optional.of(new DesktopTasksTransitionObserver(repository, transitions, shellInit))
+ Optional.of(new DesktopTasksTransitionObserver(
+ context, repository, transitions, shellInit))
);
}
@WMSingleton
@Provides
static DesktopModeLoggerTransitionObserver provideDesktopModeLoggerTransitionObserver(
+ Context context,
ShellInit shellInit,
Transitions transitions,
DesktopModeEventLogger desktopModeEventLogger) {
return new DesktopModeLoggerTransitionObserver(
- shellInit, transitions, desktopModeEventLogger);
+ context, shellInit, transitions, desktopModeEventLogger);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index a10c7c093c60..9038aaad9178 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -20,6 +20,7 @@ import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.app.TaskInfo
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.Context
import android.os.IBinder
import android.util.SparseArray
import android.view.SurfaceControl
@@ -49,6 +50,7 @@ import com.android.wm.shell.util.KtProtoLog
* and other transitions that originate both within and outside shell.
*/
class DesktopModeLoggerTransitionObserver(
+ context: Context,
shellInit: ShellInit,
private val transitions: Transitions,
private val desktopModeEventLogger: DesktopModeEventLogger
@@ -57,7 +59,8 @@ class DesktopModeLoggerTransitionObserver(
private val idSequence: InstanceIdSequence by lazy { InstanceIdSequence(Int.MAX_VALUE) }
init {
- if (Transitions.ENABLE_SHELL_TRANSITIONS && DesktopModeStatus.isEnabled()) {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS &&
+ DesktopModeStatus.canEnterDesktopMode(context)) {
shellInit.addInitCallback(this::onInit, this)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
index fcddcad3a949..9bf9fa749373 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
@@ -93,8 +93,10 @@ public class DesktopModeStatus {
"persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT);
/**
- * Return {@code true} if desktop windowing is enabled
+ * Return {@code true} if desktop windowing is enabled. Only to be used for testing. Callers
+ * should use {@link #canEnterDesktopMode(Context)} to query the state of desktop windowing.
*/
+ @VisibleForTesting
public static boolean isEnabled() {
return Flags.enableDesktopWindowingMode();
}
@@ -155,9 +157,9 @@ public class DesktopModeStatus {
}
/**
- * Return {@code true} if desktop mode can be entered on the current device.
+ * Return {@code true} if desktop mode is enabled and can be entered on the current device.
*/
public static boolean canEnterDesktopMode(@NonNull Context context) {
- return !enforceDeviceRestrictions() || isDesktopModeSupported(context);
+ return (!enforceDeviceRestrictions() || isDesktopModeSupported(context)) && isEnabled();
}
}
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 ecfb134e45a0..f7bfb86a5158 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
@@ -167,7 +167,7 @@ class DesktopTasksController(
init {
desktopMode = DesktopModeImpl()
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(context)) {
shellInit.addInitCallback({ onInit() }, this)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index 20df26428649..451e09c3cd9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.desktopmode
+import android.content.Context
import android.os.IBinder
import android.view.SurfaceControl
import android.view.WindowManager
@@ -33,13 +34,15 @@ import com.android.wm.shell.util.KtProtoLog
* and other transitions that originate both within and outside shell.
*/
class DesktopTasksTransitionObserver(
+ context: Context,
private val desktopModeTaskRepository: DesktopModeTaskRepository,
private val transitions: Transitions,
shellInit: ShellInit
) : Transitions.TransitionObserver {
init {
- if (Transitions.ENABLE_SHELL_TRANSITIONS && DesktopModeStatus.isEnabled()) {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS &&
+ DesktopModeStatus.canEnterDesktopMode(context)) {
shellInit.addInitCallback(::onInit, this)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 6fea2036dbd1..a414a55eb633 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM;
import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
import android.util.SparseArray;
import android.view.SurfaceControl;
@@ -44,6 +45,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
ShellTaskOrganizer.FocusListener {
private static final String TAG = "FreeformTaskListener";
+ private final Context mContext;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
private final WindowDecorViewModel mWindowDecorationViewModel;
@@ -56,10 +58,12 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
}
public FreeformTaskListener(
+ Context context,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
WindowDecorViewModel windowDecorationViewModel) {
+ mContext = context;
mShellTaskOrganizer = shellTaskOrganizer;
mWindowDecorationViewModel = windowDecorationViewModel;
mDesktopModeTaskRepository = desktopModeTaskRepository;
@@ -70,7 +74,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
private void onInit() {
mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FREEFORM);
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
mShellTaskOrganizer.addFocusListener(this);
}
}
@@ -92,7 +96,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
t.apply();
}
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
mDesktopModeTaskRepository.ifPresent(repository -> {
repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId);
@@ -114,7 +118,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
taskInfo.taskId);
mTasks.remove(taskInfo.taskId);
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
mDesktopModeTaskRepository.ifPresent(repository -> {
repository.removeFreeformTask(taskInfo.taskId);
repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId);
@@ -125,7 +129,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, false);
});
}
-
+ mWindowDecorationViewModel.onTaskVanished(taskInfo);
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
mWindowDecorationViewModel.destroyWindowDecoration(taskInfo);
}
@@ -139,7 +143,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
taskInfo.taskId);
mWindowDecorationViewModel.onTaskInfoChanged(taskInfo);
state.mTaskInfo = taskInfo;
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
mDesktopModeTaskRepository.ifPresent(repository -> {
if (taskInfo.isVisible) {
if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) {
@@ -161,7 +165,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG,
"Freeform Task Focus Changed: #%d focused=%b",
taskInfo.taskId, taskInfo.isFocused);
- if (DesktopModeStatus.isEnabled() && taskInfo.isFocused) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext) && taskInfo.isFocused) {
mDesktopModeTaskRepository.ifPresent(repository -> {
repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId);
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 998728d65e6a..2626e7380163 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
@@ -161,7 +161,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
taskInfo.taskId);
mTasks.remove(taskInfo.taskId);
-
+ mWindowDecorViewModelOptional.ifPresent(v -> v.onTaskVanished(taskInfo));
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
if (mWindowDecorViewModelOptional.isPresent()) {
mWindowDecorViewModelOptional.get().destroyWindowDecoration(taskInfo);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 12dce5bf70c0..8b2d0ddf2510 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -45,7 +45,6 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.util.Preconditions;
-import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
@@ -64,6 +63,9 @@ public class PipTransition extends PipTransitionController implements
private static final String TAG = PipTransition.class.getSimpleName();
private static final String PIP_TASK_TOKEN = "pip_task_token";
private static final String PIP_TASK_LEASH = "pip_task_leash";
+ private static final String PIP_START_TX = "pip_start_tx";
+ private static final String PIP_FINISH_TX = "pip_finish_tx";
+ private static final String PIP_DESTINATION_BOUNDS = "pip_dest_bounds";
/**
* The fixed start delay in ms when fading out the content overlay from bounds animation.
@@ -98,6 +100,8 @@ public class PipTransition extends PipTransitionController implements
private WindowContainerToken mPipTaskToken;
@Nullable
private SurfaceControl mPipLeash;
+ @Nullable
+ private Transitions.TransitionFinishCallback mFinishCallback;
public PipTransition(
Context context,
@@ -223,7 +227,6 @@ public class PipTransition extends PipTransitionController implements
return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback);
} else if (transition == mResizeTransition) {
mResizeTransition = null;
- mPipTransitionState.setState(PipTransitionState.CHANGING_PIP_BOUNDS);
return startResizeAnimation(info, startTransaction, finishTransaction, finishCallback);
}
@@ -246,31 +249,27 @@ public class PipTransition extends PipTransitionController implements
return false;
}
SurfaceControl pipLeash = pipChange.getLeash();
- Rect destinationBounds = pipChange.getEndAbsBounds();
// Even though the final bounds and crop are applied with finishTransaction since
// this is a visible change, we still need to handle the app draw coming in. Snapshot
// covering app draw during collection will be removed by startTransaction. So we make
- // the crop equal to the final bounds and then scale the leash back to starting bounds.
+ // the crop equal to the final bounds and then let the current
+ // animator scale the leash back to starting bounds.
+ // Note: animator is responsible for applying the startTx but NOT finishTx.
startTransaction.setWindowCrop(pipLeash, pipChange.getEndAbsBounds().width(),
pipChange.getEndAbsBounds().height());
- startTransaction.setScale(pipLeash,
- (float) mPipBoundsState.getBounds().width() / destinationBounds.width(),
- (float) mPipBoundsState.getBounds().height() / destinationBounds.height());
- startTransaction.apply();
- finishTransaction.setScale(pipLeash,
- (float) mPipBoundsState.getBounds().width() / destinationBounds.width(),
- (float) mPipBoundsState.getBounds().height() / destinationBounds.height());
-
- // We are done with the transition, but will continue animating leash to final bounds.
- finishCallback.onTransitionFinished(null);
-
- // Animate the pip leash with the new buffer
- final int duration = mContext.getResources().getInteger(
- R.integer.config_pipResizeAnimationDuration);
// TODO: b/275910498 Couple this routine with a new implementation of the PiP animator.
- startResizeAnimation(pipLeash, mPipBoundsState.getBounds(), destinationBounds, duration);
+ // Classes interested in continuing the animation would subscribe to this state update
+ // getting info such as endBounds, startTx, and finishTx as an extra Bundle once
+ // animators are in place. Once done state needs to be updated to CHANGED_PIP_BOUNDS.
+ Bundle extra = new Bundle();
+ extra.putParcelable(PIP_START_TX, startTransaction);
+ extra.putParcelable(PIP_FINISH_TX, finishTransaction);
+ extra.putParcelable(PIP_DESTINATION_BOUNDS, pipChange.getEndAbsBounds());
+
+ mFinishCallback = finishCallback;
+ mPipTransitionState.setState(PipTransitionState.CHANGING_PIP_BOUNDS, extra);
return true;
}
@@ -285,12 +284,17 @@ public class PipTransition extends PipTransitionController implements
WindowContainerToken pipTaskToken = pipChange.getContainer();
SurfaceControl pipLeash = pipChange.getLeash();
+ if (pipTaskToken == null || pipLeash == null) {
+ return false;
+ }
+
PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams;
Rect srcRectHint = params.getSourceRectHint();
Rect startBounds = pipChange.getStartAbsBounds();
Rect destinationBounds = pipChange.getEndAbsBounds();
WindowContainerTransaction finishWct = new WindowContainerTransaction();
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
if (PipBoundsAlgorithm.isSourceRectHintValidForEnterPip(srcRectHint, destinationBounds)) {
final float scale = (float) destinationBounds.width() / srcRectHint.width();
@@ -316,19 +320,17 @@ public class PipTransition extends PipTransitionController implements
.reparent(overlayLeash, pipLeash)
.setLayer(overlayLeash, Integer.MAX_VALUE);
- if (pipTaskToken != null) {
- SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(),
- this::onClientDrawAtTransitionEnd)
- .setScale(overlayLeash, 1f, 1f)
- .setPosition(overlayLeash,
- (destinationBounds.width() - overlaySize) / 2f,
- (destinationBounds.height() - overlaySize) / 2f);
- finishWct.setBoundsChangeTransaction(pipTaskToken, tx);
- }
+ // Overlay needs to be adjusted once a new draw comes in resetting surface transform.
+ tx.setScale(overlayLeash, 1f, 1f);
+ tx.setPosition(overlayLeash, (destinationBounds.width() - overlaySize) / 2f,
+ (destinationBounds.height() - overlaySize) / 2f);
}
startTransaction.apply();
+ tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(),
+ this::onClientDrawAtTransitionEnd);
+ finishWct.setBoundsChangeTransaction(pipTaskToken, tx);
+
// Note that finishWct should be free of any actual WM state changes; we are using
// it for syncing with the client draw after delayed configuration changes are dispatched.
finishCallback.onTransitionFinished(finishWct.isEmpty() ? null : finishWct);
@@ -412,14 +414,6 @@ public class PipTransition extends PipTransitionController implements
return true;
}
- /**
- * TODO: b/275910498 Use a new implementation of the PiP animator here.
- */
- private void startResizeAnimation(SurfaceControl leash, Rect startBounds,
- Rect endBounds, int duration) {
- mPipTransitionState.setState(PipTransitionState.CHANGED_PIP_BOUNDS);
- }
-
//
// Various helpers to resolve transition requests and infos
//
@@ -537,6 +531,15 @@ public class PipTransition extends PipTransitionController implements
mPipTransitionState.mPipTaskToken = null;
mPipTransitionState.mPinnedTaskLeash = null;
break;
+ case PipTransitionState.CHANGED_PIP_BOUNDS:
+ // Note: this might not be the end of the animation, rather animator just finished
+ // adjusting startTx and finishTx and is ready to finishTransition(). The animator
+ // can still continue playing the leash into the destination bounds after.
+ if (mFinishCallback != null) {
+ mFinishCallback.onTransitionFinished(null);
+ mFinishCallback = null;
+ }
+ break;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index f7bc622b6195..9a9c59e2fa8e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -257,6 +257,7 @@ public class PipTransitionState {
private String stateToString() {
switch (mState) {
case UNDEFINED: return "undefined";
+ case SWIPING_TO_PIP: return "swiping_to_pip";
case ENTERING_PIP: return "entering-pip";
case ENTERED_PIP: return "entered-pip";
case CHANGING_PIP_BOUNDS: return "changing-bounds";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index c5f23a8ed034..a8611d966a29 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -327,7 +327,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private boolean shouldEnableRunningTasksForDesktopMode() {
return mPcFeatureEnabled
- || (DesktopModeStatus.isEnabled() && enableDesktopWindowingTaskbarRunningApps());
+ || (DesktopModeStatus.canEnterDesktopMode(mContext)
+ && enableDesktopWindowingTaskbarRunningApps());
}
@VisibleForTesting
@@ -371,7 +372,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
continue;
}
- if (DesktopModeStatus.isEnabled() && mDesktopModeTaskRepository.isPresent()
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)
+ && mDesktopModeTaskRepository.isPresent()
&& mDesktopModeTaskRepository.get().isActiveTask(taskInfo.taskId)) {
if (mDesktopModeTaskRepository.get().isMinimizedTask(taskInfo.taskId)) {
// Minimized freeform tasks should not be shown at all.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 6aad4e2c9da4..8df287d12cbc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -69,7 +69,9 @@ public interface SplitScreen {
default void onSplitVisibilityChanged(boolean visible) {}
}
- /** Callback interface for listening to requests to enter split select */
+ /**
+ * Callback interface for listening to requests to enter split select. Used for desktop -> split
+ */
interface SplitSelectListener {
default boolean onRequestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
int splitPosition, Rect taskBounds) {
@@ -90,6 +92,24 @@ public interface SplitScreen {
/** Unregisters listener that gets split screen callback. */
void unregisterSplitScreenListener(@NonNull SplitScreenListener listener);
+ interface SplitInvocationListener {
+ /**
+ * Called whenever shell starts or stops the split screen animation
+ * @param animationRunning if {@code true} the animation has begun, if {@code false} the
+ * animation has finished
+ */
+ default void onSplitAnimationInvoked(boolean animationRunning) { }
+ }
+
+ /**
+ * Registers a {@link SplitInvocationListener} to notify when the animation to enter split
+ * screen has started and stopped
+ *
+ * @param executor callbacks to the listener will be executed on this executor
+ */
+ void registerSplitAnimationListener(@NonNull SplitInvocationListener listener,
+ @NonNull Executor executor);
+
/** Called when device waking up finished. */
void onFinishedWakingUp();
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 547457b018a1..b9d70e1a599d 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
@@ -1166,6 +1166,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
@Override
+ public void registerSplitAnimationListener(@NonNull SplitInvocationListener listener,
+ @NonNull Executor executor) {
+ mStageCoordinator.registerSplitAnimationListener(listener, executor);
+ }
+
+ @Override
public void onFinishedWakingUp() {
mMainExecutor.execute(SplitScreenController.this::onFinishedWakingUp);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 1a53a1d10dd2..6e5b7673e206 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -55,6 +55,7 @@ import com.android.wm.shell.transition.OneShotRemoteHandler;
import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
+import java.util.concurrent.Executor;
/** Manages transition animations for split-screen. */
class SplitScreenTransitions {
@@ -79,6 +80,8 @@ class SplitScreenTransitions {
private Transitions.TransitionFinishCallback mFinishCallback = null;
private SurfaceControl.Transaction mFinishTransaction;
+ private SplitScreen.SplitInvocationListener mSplitInvocationListener;
+ private Executor mSplitInvocationListenerExecutor;
SplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions,
@NonNull Runnable onFinishCallback, StageCoordinator stageCoordinator) {
@@ -353,6 +356,10 @@ class SplitScreenTransitions {
+ " skip to start enter split transition since it already exist. ");
return null;
}
+ if (mSplitInvocationListenerExecutor != null && mSplitInvocationListener != null) {
+ mSplitInvocationListenerExecutor.execute(() -> mSplitInvocationListener
+ .onSplitAnimationInvoked(true /*animationRunning*/));
+ }
final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
setEnterTransition(transition, remoteTransition, extraTransitType, resizeAnim);
return transition;
@@ -457,6 +464,7 @@ class SplitScreenTransitions {
mPendingEnter.onConsumed(aborted);
mPendingEnter = null;
+ mStageCoordinator.notifySplitAnimationFinished();
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTransitionConsumed for enter transition");
} else if (isPendingDismiss(transition)) {
mPendingDismiss.onConsumed(aborted);
@@ -529,6 +537,12 @@ class SplitScreenTransitions {
mTransitions.getAnimExecutor().execute(va::start);
}
+ public void registerSplitAnimListener(@NonNull SplitScreen.SplitInvocationListener listener,
+ @NonNull Executor executor) {
+ mSplitInvocationListener = listener;
+ mSplitInvocationListenerExecutor = executor;
+ }
+
/** Calls when the transition got consumed. */
interface TransitionConsumedCallback {
void onConsumed(boolean aborted);
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 5e9451a09d41..b10176df5826 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
@@ -157,6 +157,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.Executor;
/**
* Coordinates the staging (visibility, sizing, ...) of the split-screen {@link MainStage} and
@@ -237,6 +238,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private DefaultMixedHandler mMixedHandler;
private final Toast mSplitUnsupportedToast;
private SplitRequest mSplitRequest;
+ /** Used to notify others of when shell is animating into split screen */
+ private SplitScreen.SplitInvocationListener mSplitInvocationListener;
+ private Executor mSplitInvocationListenerExecutor;
/**
* Since StageCoordinator only coordinates MainStage and SideStage, it shouldn't support
@@ -247,6 +251,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return false;
}
+ /** NOTE: Will overwrite any previously set {@link #mSplitInvocationListener} */
+ public void registerSplitAnimationListener(
+ @NonNull SplitScreen.SplitInvocationListener listener, @NonNull Executor executor) {
+ mSplitInvocationListener = listener;
+ mSplitInvocationListenerExecutor = executor;
+ mSplitTransitions.registerSplitAnimListener(listener, executor);
+ }
+
class SplitRequest {
@SplitPosition
int mActivatePosition;
@@ -535,7 +547,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
null /* childrenToTop */, EXIT_REASON_UNKNOWN));
Log.w(TAG, splitFailureMessage("startShortcut",
"side stage was not populated"));
- mSplitUnsupportedToast.show();
+ handleUnsupportedSplitStart();
}
if (finishedCallback != null) {
@@ -666,7 +678,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
null /* childrenToTop */, EXIT_REASON_UNKNOWN));
Log.w(TAG, splitFailureMessage("startIntentLegacy",
"side stage was not populated"));
- mSplitUnsupportedToast.show();
+ handleUnsupportedSplitStart();
}
if (apps != null) {
@@ -1287,7 +1299,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
Log.w(TAG, splitFailureMessage("onRemoteAnimationFinishedOrCancelled",
"main or side stage was not populated."));
- mSplitUnsupportedToast.show();
+ handleUnsupportedSplitStart();
} else {
mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> {
@@ -1308,7 +1320,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
Log.w(TAG, splitFailureMessage("onRemoteAnimationFinished",
"main or side stage was not populated"));
- mSplitUnsupportedToast.show();
+ handleUnsupportedSplitStart();
return;
}
@@ -2890,6 +2902,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (hasEnteringPip) {
mMixedHandler.animatePendingEnterPipFromSplit(transition, info,
startTransaction, finishTransaction, finishCallback);
+ notifySplitAnimationFinished();
return true;
}
@@ -2924,6 +2937,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// the transition, or synchronize task-org callbacks.
}
// Use normal animations.
+ notifySplitAnimationFinished();
return false;
} else if (mMixedHandler != null && TransitionUtil.hasDisplayChange(info)) {
// A display-change has been un-expectedly inserted into the transition. Redirect
@@ -2937,6 +2951,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.update(startTransaction, true /* resetImePosition */);
startTransaction.apply();
}
+ notifySplitAnimationFinished();
return true;
}
}
@@ -3110,7 +3125,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
pendingEnter.mRemoteHandler.onTransitionConsumed(transition,
false /*aborted*/, finishT);
}
- mSplitUnsupportedToast.show();
+ handleUnsupportedSplitStart();
return true;
}
}
@@ -3139,6 +3154,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final TransitionInfo.Change finalMainChild = mainChild;
final TransitionInfo.Change finalSideChild = sideChild;
enterTransition.setFinishedCallback((callbackWct, callbackT) -> {
+ notifySplitAnimationFinished();
if (finalMainChild != null) {
if (!mainNotContainOpenTask) {
mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
@@ -3560,6 +3576,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.isLeftRightSplit());
}
+ private void handleUnsupportedSplitStart() {
+ mSplitUnsupportedToast.show();
+ notifySplitAnimationFinished();
+ }
+
+ void notifySplitAnimationFinished() {
+ if (mSplitInvocationListener == null || mSplitInvocationListenerExecutor == null) {
+ return;
+ }
+ mSplitInvocationListenerExecutor.execute(() ->
+ mSplitInvocationListener.onSplitAnimationInvoked(false /*animationRunning*/));
+ }
+
/**
* Logs the exit of splitscreen to a specific stage. This must be called before the exit is
* executed.
@@ -3622,7 +3651,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!ENABLE_SHELL_TRANSITIONS) {
StageCoordinator.this.exitSplitScreen(isMainStage ? mMainStage : mSideStage,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
- mSplitUnsupportedToast.show();
+ handleUnsupportedSplitStart();
return;
}
@@ -3642,7 +3671,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
"app package " + taskInfo.baseActivity.getPackageName()
+ " does not support splitscreen, or is a controlled activity type"));
if (splitScreenVisible) {
- mSplitUnsupportedToast.show();
+ handleUnsupportedSplitStart();
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index f41bca36bb70..1e305c5dbbcf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -260,6 +260,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%d", taskInfo.taskId);
final int taskId = taskInfo.taskId;
+ mWindowDecorViewModel.ifPresent(vm -> vm.onTaskVanished(taskInfo));
if (mRootTaskInfo.taskId == taskId) {
mCallbacks.onRootTaskVanished();
mRootTaskInfo = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 9b2922dff2f5..4d3c76322fa8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -61,6 +61,7 @@ import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.ITransitionPlayer;
import android.window.RemoteTransition;
+import android.window.TaskFragmentOrganizer;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
import android.window.TransitionMetrics;
@@ -183,6 +184,13 @@ public class Transitions implements RemoteCallable<Transitions>,
/** Transition to resize PiP task. */
public static final int TRANSIT_RESIZE_PIP = TRANSIT_FIRST_CUSTOM + 16;
+ /**
+ * The task fragment drag resize transition used by activity embedding.
+ */
+ public static final int TRANSIT_TASK_FRAGMENT_DRAG_RESIZE =
+ // TRANSIT_FIRST_CUSTOM + 17
+ TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_DRAG_RESIZE;
+
private final ShellTaskOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 87dc3915082f..e85cb6400000 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -119,6 +119,21 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
}
@Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ // A task vanishing doesn't necessarily mean the task was closed, it could also mean its
+ // windowing mode changed. We're only interested in closing tasks so checking whether
+ // its info still exists in the task organizer is one way to disambiguate.
+ final boolean closed = mTaskOrganizer.getRunningTaskInfo(taskInfo.taskId) == null;
+ if (closed) {
+ // Destroying the window decoration is usually handled when a TRANSIT_CLOSE transition
+ // changes happen, but there are certain cases in which closing tasks aren't included
+ // in transitions, such as when a non-visible task is closed. See b/296921167.
+ // Destroy the decoration here in case the lack of transition missed it.
+ destroyWindowDecoration(taskInfo);
+ }
+ }
+
+ @Override
public void onTaskChanging(
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 01175f598089..f3ef7c17fac3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -35,6 +35,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.compatui.AppCompatUtils.isSingleTopActivityTranslucent;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import android.annotation.NonNull;
@@ -72,6 +73,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
@@ -276,7 +278,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
if (visible && stage != STAGE_TYPE_UNDEFINED) {
DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId);
- if (decor != null && DesktopModeStatus.isEnabled()) {
+ if (decor != null && DesktopModeStatus.canEnterDesktopMode(mContext)) {
mDesktopTasksController.moveToSplit(decor.mTaskInfo);
}
}
@@ -309,6 +311,22 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
@Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ // A task vanishing doesn't necessarily mean the task was closed, it could also mean its
+ // windowing mode changed. We're only interested in closing tasks so checking whether
+ // its info still exists in the task organizer is one way to disambiguate.
+ final boolean closed = mTaskOrganizer.getRunningTaskInfo(taskInfo.taskId) == null;
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "Task Vanished: #%d closed=%b", taskInfo.taskId, closed);
+ if (closed) {
+ // Destroying the window decoration is usually handled when a TRANSIT_CLOSE transition
+ // changes happen, but there are certain cases in which closing tasks aren't included
+ // in transitions, such as when a non-visible task is closed. See b/296921167.
+ // Destroy the decoration here in case the lack of transition missed it.
+ destroyWindowDecoration(taskInfo);
+ }
+ }
+
+ @Override
public void onTaskChanging(
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
@@ -594,7 +612,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
final RunningTaskInfo taskInfo = decoration.mTaskInfo;
- if (DesktopModeStatus.isEnabled()
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
return false;
}
@@ -771,7 +789,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
*/
private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) {
final DesktopModeWindowDecoration relevantDecor = getRelevantWindowDecor(ev);
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
if (!mInImmersiveMode && (relevantDecor == null
|| relevantDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM
|| mTransitionDragActive)) {
@@ -780,7 +798,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
handleEventOutsideCaption(ev, relevantDecor);
// Prevent status bar from reacting to a caption drag.
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
if (mTransitionDragActive) {
inputMonitor.pilferPointers();
}
@@ -838,7 +856,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDragToDesktopAnimationStartBounds.set(
relevantDecor.mTaskInfo.configuration.windowConfiguration.getBounds());
boolean dragFromStatusBarAllowed = false;
- if (DesktopModeStatus.isEnabled()) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
// In proto2 any full screen or multi-window task can be dragged to
// freeform.
final int windowingMode = relevantDecor.mTaskInfo.getWindowingMode();
@@ -1013,12 +1031,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
&& isSingleTopActivityTranslucent(taskInfo)) {
return false;
}
- return DesktopModeStatus.isEnabled()
+ return DesktopModeStatus.canEnterDesktopMode(mContext)
&& !DesktopWallpaperActivity.isWallpaperTask(taskInfo)
&& taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
&& taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
- && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop()
- && DesktopModeStatus.canEnterDesktopMode(mContext);
+ && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop();
}
private void createWindowDecoration(
@@ -1087,7 +1104,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + "DesktopModeWindowDecorViewModel");
- pw.println(innerPrefix + "DesktopModeStatus=" + DesktopModeStatus.isEnabled());
+ pw.println(innerPrefix + "DesktopModeStatus="
+ + DesktopModeStatus.canEnterDesktopMode(mContext));
pw.println(innerPrefix + "mTransitionDragActive=" + mTransitionDragActive);
pw.println(innerPrefix + "mEventReceiversByDisplay=" + mEventReceiversByDisplay);
pw.println(innerPrefix + "mWindowDecorByTaskId=" + mWindowDecorByTaskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 8c6bc73d10bf..f7516dabe1ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -638,7 +638,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
.setOnClickListener(mOnCaptionButtonClickListener)
.setOnTouchListener(mOnCaptionTouchListener)
.setLayoutId(mRelayoutParams.mLayoutResId)
- .setWindowingButtonsVisible(DesktopModeStatus.isEnabled())
+ .setWindowingButtonsVisible(DesktopModeStatus.canEnterDesktopMode(mContext))
.setCaptionHeight(mResult.mCaptionHeight)
.build();
mWindowDecorViewHolder.onHandleMenuOpened();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index 01a6012ea314..1563259f4a1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -67,6 +67,14 @@ public interface WindowDecorViewModel {
void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo);
/**
+ * Notifies a task has vanished, which can mean that the task changed windowing mode or was
+ * removed.
+ *
+ * @param taskInfo the task info of the task
+ */
+ void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo);
+
+ /**
* Notifies a transition is about to start about the given task to give the window decoration a
* chance to prepare for this transition. Unlike {@link #onTaskInfoChanged}, this method creates
* a window decoration if one does not exist but is required.
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 0f24bb549158..b8a19ad35307 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -13,3 +13,5 @@ nmusgrave@google.com
pbdr@google.com
tkachenkoi@google.com
mpodolian@google.com
+jeremysim@google.com
+peanutbutter@google.com
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
index 2ac72affbb0c..ea522cdf2509 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
@@ -20,6 +20,8 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -100,6 +102,20 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim
}
@Test
+ public void testTransitionTypeDragResize() {
+ final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TASK_FRAGMENT_DRAG_RESIZE, 0)
+ .addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY))
+ .build();
+ final Animator animator = mAnimRunner.createAnimator(
+ info, mStartTransaction, mFinishTransaction,
+ () -> mFinishCallback.onTransitionFinished(null /* wct */),
+ new ArrayList());
+
+ // The animation should be empty when it is a jump cut for drag resize.
+ assertEquals(0, animator.getDuration());
+ }
+
+ @Test
public void testInvalidCustomAnimation() {
final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
.addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 56d0f8e13f08..8de60b7acc91 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -115,27 +115,27 @@ public class SplitLayoutTests extends ShellTestCase {
@Test
public void testUpdateDivideBounds() {
- mSplitLayout.updateDivideBounds(anyInt());
+ mSplitLayout.updateDividerBounds(anyInt());
verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class), anyInt(),
anyInt());
}
@Test
public void testSetDividePosition() {
- mSplitLayout.setDividePosition(100, false /* applyLayoutChange */);
- assertThat(mSplitLayout.getDividePosition()).isEqualTo(100);
+ mSplitLayout.setDividerPosition(100, false /* applyLayoutChange */);
+ assertThat(mSplitLayout.getDividerPosition()).isEqualTo(100);
verify(mSplitLayoutHandler, never()).onLayoutSizeChanged(any(SplitLayout.class));
- mSplitLayout.setDividePosition(200, true /* applyLayoutChange */);
- assertThat(mSplitLayout.getDividePosition()).isEqualTo(200);
+ mSplitLayout.setDividerPosition(200, true /* applyLayoutChange */);
+ assertThat(mSplitLayout.getDividerPosition()).isEqualTo(200);
verify(mSplitLayoutHandler).onLayoutSizeChanged(any(SplitLayout.class));
}
@Test
public void testSetDivideRatio() {
- mSplitLayout.setDividePosition(200, false /* applyLayoutChange */);
+ mSplitLayout.setDividerPosition(200, false /* applyLayoutChange */);
mSplitLayout.setDivideRatio(SNAP_TO_50_50);
- assertThat(mSplitLayout.getDividePosition()).isEqualTo(
+ assertThat(mSplitLayout.getDividerPosition()).isEqualTo(
mSplitLayout.mDividerSnapAlgorithm.getMiddleTarget().position);
}
@@ -152,7 +152,7 @@ public class SplitLayoutTests extends ShellTestCase {
DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
SNAP_TO_START_AND_DISMISS);
- mSplitLayout.snapToTarget(mSplitLayout.getDividePosition(), snapTarget);
+ mSplitLayout.snapToTarget(mSplitLayout.getDividerPosition(), snapTarget);
waitDividerFlingFinished();
verify(mSplitLayoutHandler).onSnappedToDismiss(eq(false), anyInt());
}
@@ -164,7 +164,7 @@ public class SplitLayoutTests extends ShellTestCase {
DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
SNAP_TO_END_AND_DISMISS);
- mSplitLayout.snapToTarget(mSplitLayout.getDividePosition(), snapTarget);
+ mSplitLayout.snapToTarget(mSplitLayout.getDividerPosition(), snapTarget);
waitDividerFlingFinished();
verify(mSplitLayoutHandler).onSnappedToDismiss(eq(true), anyInt());
}
@@ -188,7 +188,7 @@ public class SplitLayoutTests extends ShellTestCase {
}
private void waitDividerFlingFinished() {
- verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), anyInt(),
+ verify(mSplitLayout).flingDividerPosition(anyInt(), anyInt(), anyInt(),
mRunnableCaptor.capture());
mRunnableCaptor.getValue().run();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index 5209d0e4bdd0..41a81c1a9921 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -22,6 +22,7 @@ import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_A
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -98,14 +99,28 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
private CompatUIWindowManager mWindowManager;
private TaskInfo mTaskInfo;
+ private DisplayLayout mDisplayLayout;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
doReturn(100).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance();
mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN);
+
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = TASK_WIDTH;
+ displayInfo.logicalHeight = TASK_HEIGHT;
+ mDisplayLayout = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);
+ final InsetsState insetsState = new InsetsState();
+ insetsState.setDisplayFrame(new Rect(0, 0, TASK_WIDTH, TASK_HEIGHT));
+ final InsetsSource insetsSource = new InsetsSource(
+ InsetsSource.createId(null, 0, navigationBars()), navigationBars());
+ insetsSource.setFrame(0, TASK_HEIGHT - 200, TASK_WIDTH, TASK_HEIGHT);
+ insetsState.addSource(insetsSource);
+ mDisplayLayout.setInsets(mContext.getResources(), insetsState);
mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
- mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
+ mCallback, mTaskListener, mDisplayLayout, new CompatUIHintsState(),
mCompatUIConfiguration, mOnRestartButtonClicked);
spyOn(mWindowManager);
@@ -363,9 +378,9 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
// Update if the insets change on the existing display layout
clearInvocations(mWindowManager);
- InsetsState insetsState = new InsetsState();
+ final InsetsState insetsState = new InsetsState();
insetsState.setDisplayFrame(new Rect(0, 0, 1000, 2000));
- InsetsSource insetsSource = new InsetsSource(
+ final InsetsSource insetsSource = new InsetsSource(
InsetsSource.createId(null, 0, navigationBars()), navigationBars());
insetsSource.setFrame(0, 1800, 1000, 2000);
insetsState.addSource(insetsSource);
@@ -493,16 +508,14 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
@Test
public void testShouldShowSizeCompatRestartButton() {
mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_HIDE_SCM_BUTTON);
-
- doReturn(86).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance();
+ doReturn(85).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance();
mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
- mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
+ mCallback, mTaskListener, mDisplayLayout, new CompatUIHintsState(),
mCompatUIConfiguration, mOnRestartButtonClicked);
// Simulate rotation of activity in square display
TaskInfo taskInfo = createTaskInfo(true, CAMERA_COMPAT_CONTROL_HIDDEN);
- taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 2000, 2000));
- taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 2000;
+ taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = TASK_HEIGHT;
taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1850;
assertFalse(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));
@@ -512,11 +525,21 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
assertTrue(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));
// Simulate folding
- taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 1000, 2000));
- assertFalse(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));
+ final InsetsState insetsState = new InsetsState();
+ insetsState.setDisplayFrame(new Rect(0, 0, 1000, TASK_HEIGHT));
+ final InsetsSource insetsSource = new InsetsSource(
+ InsetsSource.createId(null, 0, navigationBars()), navigationBars());
+ insetsSource.setFrame(0, TASK_HEIGHT - 200, 1000, TASK_HEIGHT);
+ insetsState.addSource(insetsSource);
+ mDisplayLayout.setInsets(mContext.getResources(), insetsState);
+ mWindowManager.updateDisplayLayout(mDisplayLayout);
+ taskInfo.configuration.smallestScreenWidthDp = LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 100;
+ assertTrue(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));
- taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1000;
- taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 500;
+ // Simulate floating app with 90& area, more than tolerance
+ taskInfo.configuration.smallestScreenWidthDp = LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
+ taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 950;
+ taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 1900;
assertTrue(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));
}
@@ -529,10 +552,10 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
cameraCompatControlState;
taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
// Letterboxed activity that takes half the screen should show size compat restart button
- taskInfo.configuration.windowConfiguration.setBounds(
- new Rect(0, 0, TASK_WIDTH, TASK_HEIGHT));
taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 1000;
taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1000;
+ // Screen width dp larger than a normal phone.
+ taskInfo.configuration.smallestScreenWidthDp = LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
return taskInfo;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index 65117f7e9eea..60a7dcda5351 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.desktopmode
import android.app.ActivityManager
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.content.Context
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.SurfaceControl
@@ -35,6 +36,7 @@ import android.window.TransitionInfo
import android.window.TransitionInfo.Change
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
import com.android.modules.utils.testing.ExtendedMockitoRule
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
@@ -58,6 +60,11 @@ import org.mockito.kotlin.never
import org.mockito.kotlin.same
import org.mockito.kotlin.times
+/**
+ * Test class for {@link DesktopModeLoggerTransitionObserver}
+ *
+ * Usage: atest WMShellUnitTests:DesktopModeLoggerTransitionObserverTest
+ */
@SmallTest
@RunWith(AndroidTestingRunner::class)
class DesktopModeLoggerTransitionObserverTest {
@@ -74,6 +81,8 @@ class DesktopModeLoggerTransitionObserverTest {
private lateinit var mockShellInit: ShellInit
@Mock
private lateinit var transitions: Transitions
+ @Mock
+ private lateinit var context: Context
private lateinit var transitionObserver: DesktopModeLoggerTransitionObserver
private lateinit var shellInit: ShellInit
@@ -81,12 +90,12 @@ class DesktopModeLoggerTransitionObserverTest {
@Before
fun setup() {
- Mockito.`when`(DesktopModeStatus.isEnabled()).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(any()) }
shellInit = Mockito.spy(ShellInit(testExecutor))
desktopModeEventLogger = mock(DesktopModeEventLogger::class.java)
transitionObserver = DesktopModeLoggerTransitionObserver(
- mockShellInit, transitions, desktopModeEventLogger)
+ context, mockShellInit, transitions, desktopModeEventLogger)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
val initRunnableCaptor = ArgumentCaptor.forClass(
Runnable::class.java)
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 ad4b720facd7..df8a2223dadc 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
@@ -159,6 +159,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
mockitoSession = mockitoSession().strictness(Strictness.LENIENT)
.spyStatic(DesktopModeStatus::class.java).startMocking()
whenever(DesktopModeStatus.isEnabled()).thenReturn(true)
+ doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
shellInit = Mockito.spy(ShellInit(testExecutor))
desktopModeTaskRepository = DesktopModeTaskRepository()
@@ -1347,7 +1348,6 @@ class DesktopTasksControllerTest : ShellTestCase() {
private fun setUpFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
val task = createFullscreenTask(displayId)
- doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
runningTasks.add(task)
@@ -1356,7 +1356,6 @@ class DesktopTasksControllerTest : ShellTestCase() {
private fun setUpSplitScreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
val task = createSplitScreenTask(displayId)
- doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
whenever(splitScreenController.isTaskInSplitScreen(task.taskId)).thenReturn(true)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
index 38ea03471b07..539d5b86453f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
@@ -27,6 +27,7 @@ import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
@@ -41,6 +42,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.any
import org.mockito.Mockito.`when`
import org.mockito.quality.Strictness
@@ -69,7 +71,7 @@ class DesktopTasksLimiterTest : ShellTestCase() {
fun setUp() {
mockitoSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
.spyStatic(DesktopModeStatus::class.java).startMocking()
- `when`(DesktopModeStatus.isEnabled()).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(any()) }
desktopTaskRepo = DesktopModeTaskRepository()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
index 71eea4bb59b1..665077be3af7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
@@ -19,11 +19,12 @@ package com.android.wm.shell.freeform;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.app.ActivityManager;
@@ -72,8 +73,10 @@ public final class FreeformTaskListenerTests extends ShellTestCase {
public void setup() {
mMockitoSession = mockitoSession().initMocks(this)
.strictness(Strictness.LENIENT).mockStatic(DesktopModeStatus.class).startMocking();
- when(DesktopModeStatus.isEnabled()).thenReturn(true);
+ doReturn(true).when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
+
mFreeformTaskListener = new FreeformTaskListener(
+ mContext,
mShellInit,
mTaskOrganizer,
Optional.of(mDesktopModeTaskRepository),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 5cf9be4e7aca..240324ba4420 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -59,6 +59,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -75,11 +76,13 @@ import com.android.wm.shell.sysui.ShellSharedConstants;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.SplitBounds;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.Arrays;
@@ -88,7 +91,9 @@ import java.util.Optional;
import java.util.function.Consumer;
/**
- * Tests for {@link RecentTasksController}.
+ * Tests for {@link RecentTasksController}
+ *
+ * Usage: atest WMShellUnitTests:RecentTasksControllerTest
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -118,9 +123,15 @@ public class RecentTasksControllerTest extends ShellTestCase {
private ShellInit mShellInit;
private ShellController mShellController;
private TestShellExecutor mMainExecutor;
+ private static StaticMockitoSession sMockitoSession;
@Before
public void setUp() {
+ sMockitoSession = mockitoSession().initMocks(this).strictness(Strictness.LENIENT)
+ .mockStatic(DesktopModeStatus.class).startMocking();
+ ExtendedMockito.doReturn(true)
+ .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
+
mMainExecutor = new TestShellExecutor();
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
mShellInit = spy(new ShellInit(mMainExecutor));
@@ -136,6 +147,11 @@ public class RecentTasksControllerTest extends ShellTestCase {
mShellInit.init();
}
+ @After
+ public void tearDown() {
+ sMockitoSession.finishMocking();
+ }
+
@Test
public void instantiateController_addInitCallback() {
verify(mShellInit, times(1)).addInitCallback(any(), isA(RecentTasksController.class));
@@ -275,10 +291,6 @@ public class RecentTasksControllerTest extends ShellTestCase {
@Test
public void testGetRecentTasks_hasActiveDesktopTasks_proto2Enabled_groupFreeformTasks() {
- StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
- DesktopModeStatus.class).startMocking();
- when(DesktopModeStatus.isEnabled()).thenReturn(true);
-
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
@@ -309,16 +321,10 @@ public class RecentTasksControllerTest extends ShellTestCase {
// Check single entries
assertEquals(t2, singleGroup1.getTaskInfo1());
assertEquals(t4, singleGroup2.getTaskInfo1());
-
- mockitoSession.finishMocking();
}
@Test
public void testGetRecentTasks_hasActiveDesktopTasks_proto2Enabled_freeformTaskOrder() {
- StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
- DesktopModeStatus.class).startMocking();
- when(DesktopModeStatus.isEnabled()).thenReturn(true);
-
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
@@ -357,15 +363,12 @@ public class RecentTasksControllerTest extends ShellTestCase {
// Check single entry
assertEquals(t4, singleGroup.getTaskInfo1());
-
- mockitoSession.finishMocking();
}
@Test
public void testGetRecentTasks_hasActiveDesktopTasks_proto2Disabled_doNotGroupFreeformTasks() {
- StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
- DesktopModeStatus.class).startMocking();
- when(DesktopModeStatus.isEnabled()).thenReturn(false);
+ ExtendedMockito.doReturn(false)
+ .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -390,16 +393,10 @@ public class RecentTasksControllerTest extends ShellTestCase {
assertEquals(t2, recentTasks.get(1).getTaskInfo1());
assertEquals(t3, recentTasks.get(2).getTaskInfo1());
assertEquals(t4, recentTasks.get(3).getTaskInfo1());
-
- mockitoSession.finishMocking();
}
@Test
public void testGetRecentTasks_proto2Enabled_ignoresMinimizedFreeformTasks() {
- StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
- DesktopModeStatus.class).startMocking();
- when(DesktopModeStatus.isEnabled()).thenReturn(true);
-
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
@@ -435,8 +432,6 @@ public class RecentTasksControllerTest extends ShellTestCase {
// Check single entries
assertEquals(t2, singleGroup1.getTaskInfo1());
assertEquals(t4, singleGroup2.getTaskInfo1());
-
- mockitoSession.finishMocking();
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index befc702b01aa..34b2eebb15a1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -39,10 +39,13 @@ import static org.junit.Assert.assertNull;
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.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -63,6 +66,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
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;
@@ -105,6 +109,8 @@ public class SplitTransitionTests extends ShellTestCase {
@Mock private ShellExecutor mMainExecutor;
@Mock private LaunchAdjacentController mLaunchAdjacentController;
@Mock private DefaultMixedHandler mMixedHandler;
+ @Mock private SplitScreen.SplitInvocationListener mInvocationListener;
+ private final TestShellExecutor mTestShellExecutor = new TestShellExecutor();
private SplitLayout mSplitLayout;
private MainStage mMainStage;
private SideStage mSideStage;
@@ -147,6 +153,7 @@ public class SplitTransitionTests extends ShellTestCase {
.setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager();
doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager();
+ mStageCoordinator.registerSplitAnimationListener(mInvocationListener, mTestShellExecutor);
}
@Test
@@ -452,6 +459,15 @@ public class SplitTransitionTests extends ShellTestCase {
mMainStage.activate(new WindowContainerTransaction(), true /* includingTopTask */);
}
+ @Test
+ @UiThreadTest
+ public void testSplitInvocationCallback() {
+ enterSplit();
+ mTestShellExecutor.flushAll();
+ verify(mInvocationListener, times(1))
+ .onSplitAnimationInvoked(eq(true));
+ }
+
private boolean containsSplitEnter(@NonNull WindowContainerTransaction wct) {
for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index f9dc5fac7e21..f97992f7c9d1 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -24,7 +24,6 @@
#include <SkColor.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
-#include <com_android_input_flags.h>
#include <ftl/enum.h>
#include <mutex>
@@ -35,14 +34,10 @@
#define INDENT2 " "
#define INDENT3 " "
-namespace input_flags = com::android::input::flags;
-
namespace android {
namespace {
-static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
-
const ui::Transform kIdentityTransform;
} // namespace
@@ -68,27 +63,24 @@ void PointerController::DisplayInfoListener::onPointerControllerDestroyed() {
std::shared_ptr<PointerController> PointerController::create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled, ControllerType type) {
+ SpriteController& spriteController, ControllerType type) {
// using 'new' to access non-public constructor
std::shared_ptr<PointerController> controller;
switch (type) {
case ControllerType::MOUSE:
controller = std::shared_ptr<PointerController>(
- new MousePointerController(policy, looper, spriteController, enabled));
+ new MousePointerController(policy, looper, spriteController));
break;
case ControllerType::TOUCH:
controller = std::shared_ptr<PointerController>(
- new TouchPointerController(policy, looper, spriteController, enabled));
+ new TouchPointerController(policy, looper, spriteController));
break;
case ControllerType::STYLUS:
controller = std::shared_ptr<PointerController>(
- new StylusPointerController(policy, looper, spriteController, enabled));
+ new StylusPointerController(policy, looper, spriteController));
break;
- case ControllerType::LEGACY:
default:
- controller = std::shared_ptr<PointerController>(
- new PointerController(policy, looper, spriteController, enabled));
- break;
+ LOG_ALWAYS_FATAL("Invalid ControllerType: %d", static_cast<int>(type));
}
/*
@@ -108,10 +100,9 @@ std::shared_ptr<PointerController> PointerController::create(
}
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, SpriteController& spriteController,
- bool enabled)
+ const sp<Looper>& looper, SpriteController& spriteController)
: PointerController(
- policy, looper, spriteController, enabled,
+ policy, looper, spriteController,
[](const sp<android::gui::WindowInfosListener>& listener) {
auto initialInfo = std::make_pair(std::vector<android::gui::WindowInfo>{},
std::vector<android::gui::DisplayInfo>{});
@@ -125,11 +116,9 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper, SpriteController& spriteController,
- bool enabled,
const WindowListenerRegisterConsumer& registerListener,
WindowListenerUnregisterConsumer unregisterListener)
- : mEnabled(enabled),
- mContext(policy, looper, spriteController, *this),
+ : mContext(policy, looper, spriteController, *this),
mCursorController(mContext),
mDisplayInfoListener(sp<DisplayInfoListener>::make(this)),
mUnregisterWindowInfosListener(std::move(unregisterListener)) {
@@ -142,7 +131,6 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
PointerController::~PointerController() {
mDisplayInfoListener->onPointerControllerDestroyed();
mUnregisterWindowInfosListener(mDisplayInfoListener);
- mContext.getPolicy()->onPointerDisplayIdChanged(ADISPLAY_ID_NONE, FloatPoint{0, 0});
}
std::mutex& PointerController::getLock() const {
@@ -150,14 +138,10 @@ std::mutex& PointerController::getLock() const {
}
std::optional<FloatRect> PointerController::getBounds() const {
- if (!mEnabled) return {};
-
return mCursorController.getBounds();
}
void PointerController::move(float deltaX, float deltaY) {
- if (!mEnabled) return;
-
const int32_t displayId = mCursorController.getDisplayId();
vec2 transformed;
{
@@ -169,8 +153,6 @@ void PointerController::move(float deltaX, float deltaY) {
}
void PointerController::setPosition(float x, float y) {
- if (!mEnabled) return;
-
const int32_t displayId = mCursorController.getDisplayId();
vec2 transformed;
{
@@ -182,10 +164,6 @@ void PointerController::setPosition(float x, float y) {
}
FloatPoint PointerController::getPosition() const {
- if (!mEnabled) {
- return FloatPoint{0, 0};
- }
-
const int32_t displayId = mCursorController.getDisplayId();
const auto p = mCursorController.getPosition();
{
@@ -196,28 +174,20 @@ FloatPoint PointerController::getPosition() const {
}
int32_t PointerController::getDisplayId() const {
- if (!mEnabled) return ADISPLAY_ID_NONE;
-
return mCursorController.getDisplayId();
}
void PointerController::fade(Transition transition) {
- if (!mEnabled) return;
-
std::scoped_lock lock(getLock());
mCursorController.fade(transition);
}
void PointerController::unfade(Transition transition) {
- if (!mEnabled) return;
-
std::scoped_lock lock(getLock());
mCursorController.unfade(transition);
}
void PointerController::setPresentation(Presentation presentation) {
- if (!mEnabled) return;
-
std::scoped_lock lock(getLock());
if (mLocked.presentation == presentation) {
@@ -226,33 +196,13 @@ void PointerController::setPresentation(Presentation presentation) {
mLocked.presentation = presentation;
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- // When pointer choreographer is enabled, the presentation mode is only set once when the
- // PointerController is constructed, before the display viewport is provided.
- // TODO(b/293587049): Clean up the PointerController interface after pointer choreographer
- // is permanently enabled. The presentation can be set in the constructor.
- mCursorController.setStylusHoverMode(presentation == Presentation::STYLUS_HOVER);
- return;
- }
-
- if (!mCursorController.isViewportValid()) {
- return;
- }
-
- if (presentation == Presentation::POINTER || presentation == Presentation::STYLUS_HOVER) {
- // For now, we support stylus hover using the mouse cursor implementation.
- // TODO: Add proper support for stylus hover icons.
- mCursorController.setStylusHoverMode(presentation == Presentation::STYLUS_HOVER);
-
- mCursorController.getAdditionalMouseResources();
- clearSpotsLocked();
- }
+ // The presentation mode is only set once when the PointerController is constructed,
+ // before the display viewport is provided.
+ mCursorController.setStylusHoverMode(presentation == Presentation::STYLUS_HOVER);
}
void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
BitSet32 spotIdBits, int32_t displayId) {
- if (!mEnabled) return;
-
std::scoped_lock lock(getLock());
std::array<PointerCoords, MAX_POINTERS> outSpotCoords{};
const ui::Transform& transform = getTransformForDisplayLocked(displayId);
@@ -272,12 +222,13 @@ void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t
if (it == mLocked.spotControllers.end()) {
mLocked.spotControllers.try_emplace(displayId, displayId, mContext);
}
- mLocked.spotControllers.at(displayId).setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits);
+ bool skipScreenshot = mLocked.displaysToSkipScreenshot.find(displayId) !=
+ mLocked.displaysToSkipScreenshot.end();
+ mLocked.spotControllers.at(displayId).setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits,
+ skipScreenshot);
}
void PointerController::clearSpots() {
- if (!mEnabled) return;
-
std::scoped_lock lock(getLock());
clearSpotsLocked();
}
@@ -310,12 +261,6 @@ void PointerController::reloadPointerResources() {
}
void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
- struct PointerDisplayChangeArgs {
- int32_t displayId;
- FloatPoint cursorPosition;
- };
- std::optional<PointerDisplayChangeArgs> pointerDisplayChanged;
-
{ // acquire lock
std::scoped_lock lock(getLock());
@@ -327,31 +272,29 @@ void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources);
if (viewport.displayId != mLocked.pointerDisplayId) {
mLocked.pointerDisplayId = viewport.displayId;
- pointerDisplayChanged = {viewport.displayId, mCursorController.getPosition()};
}
} // release lock
-
- if (pointerDisplayChanged) {
- // Notify the policy without holding the pointer controller lock.
- mContext.getPolicy()->onPointerDisplayIdChanged(pointerDisplayChanged->displayId,
- pointerDisplayChanged->cursorPosition);
- }
}
void PointerController::updatePointerIcon(PointerIconStyle iconId) {
- if (!mEnabled) return;
-
std::scoped_lock lock(getLock());
mCursorController.updatePointerIcon(iconId);
}
void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
- if (!mEnabled) return;
-
std::scoped_lock lock(getLock());
mCursorController.setCustomPointerIcon(icon);
}
+void PointerController::setSkipScreenshot(int32_t displayId, bool skip) {
+ std::scoped_lock lock(getLock());
+ if (skip) {
+ mLocked.displaysToSkipScreenshot.insert(displayId);
+ } else {
+ mLocked.displaysToSkipScreenshot.erase(displayId);
+ }
+}
+
void PointerController::doInactivityTimeout() {
fade(Transition::GRADUAL);
}
@@ -392,10 +335,6 @@ const ui::Transform& PointerController::getTransformForDisplayLocked(int display
}
std::string PointerController::dump() {
- if (!mEnabled) {
- return INDENT "PointerController: DISABLED due to ongoing PointerChoreographer refactor\n";
- }
-
std::string dump = INDENT "PointerController:\n";
std::scoped_lock lock(getLock());
dump += StringPrintf(INDENT2 "Presentation: %s\n",
@@ -416,8 +355,8 @@ std::string PointerController::dump() {
MousePointerController::MousePointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled)
- : PointerController(policy, looper, spriteController, enabled) {
+ SpriteController& spriteController)
+ : PointerController(policy, looper, spriteController) {
PointerController::setPresentation(Presentation::POINTER);
}
@@ -429,8 +368,8 @@ MousePointerController::~MousePointerController() {
TouchPointerController::TouchPointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled)
- : PointerController(policy, looper, spriteController, enabled) {
+ SpriteController& spriteController)
+ : PointerController(policy, looper, spriteController) {
PointerController::setPresentation(Presentation::SPOT);
}
@@ -442,8 +381,8 @@ TouchPointerController::~TouchPointerController() {
StylusPointerController::StylusPointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled)
- : PointerController(policy, looper, spriteController, enabled) {
+ SpriteController& spriteController)
+ : PointerController(policy, looper, spriteController) {
PointerController::setPresentation(Presentation::STYLUS_HOVER);
}
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 6ee5707622ca..eaf34d527396 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -47,8 +47,7 @@ class PointerController : public PointerControllerInterface {
public:
static std::shared_ptr<PointerController> create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled,
- ControllerType type = ControllerType::LEGACY);
+ SpriteController& spriteController, ControllerType type);
~PointerController() override;
@@ -67,6 +66,7 @@ public:
void clearSpots() override;
void updatePointerIcon(PointerIconStyle iconId) override;
void setCustomPointerIcon(const SpriteIcon& icon) override;
+ void setSkipScreenshot(int32_t displayId, bool skip) override;
virtual void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void doInactivityTimeout();
@@ -86,12 +86,12 @@ protected:
// Constructor used to test WindowInfosListener registration.
PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled,
+ SpriteController& spriteController,
const WindowListenerRegisterConsumer& registerListener,
WindowListenerUnregisterConsumer unregisterListener);
PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- SpriteController& spriteController, bool enabled);
+ SpriteController& spriteController);
private:
friend PointerControllerContext::LooperCallback;
@@ -103,8 +103,6 @@ private:
// we use the DisplayInfoListener's lock in PointerController.
std::mutex& getLock() const;
- const bool mEnabled;
-
PointerControllerContext mContext;
MouseCursorController mCursorController;
@@ -115,6 +113,7 @@ private:
std::vector<gui::DisplayInfo> mDisplayInfos;
std::unordered_map<int32_t /* displayId */, TouchSpotController> spotControllers;
+ std::unordered_set<int32_t /* displayId */> displaysToSkipScreenshot;
} mLocked GUARDED_BY(getLock());
class DisplayInfoListener : public gui::WindowInfosListener {
@@ -142,8 +141,7 @@ class MousePointerController : public PointerController {
public:
/** A version of PointerController that controls one mouse pointer. */
MousePointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, SpriteController& spriteController,
- bool enabled);
+ const sp<Looper>& looper, SpriteController& spriteController);
~MousePointerController() override;
@@ -162,8 +160,7 @@ class TouchPointerController : public PointerController {
public:
/** A version of PointerController that controls touch spots. */
TouchPointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, SpriteController& spriteController,
- bool enabled);
+ const sp<Looper>& looper, SpriteController& spriteController);
~TouchPointerController() override;
@@ -208,8 +205,7 @@ class StylusPointerController : public PointerController {
public:
/** A version of PointerController that controls one stylus pointer. */
StylusPointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, SpriteController& spriteController,
- bool enabled);
+ const sp<Looper>& looper, SpriteController& spriteController);
~StylusPointerController() override;
diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h
index 98c3988e7df4..e893c49d80e5 100644
--- a/libs/input/PointerControllerContext.h
+++ b/libs/input/PointerControllerContext.h
@@ -81,7 +81,6 @@ public:
virtual PointerIconStyle getDefaultPointerIconId() = 0;
virtual PointerIconStyle getDefaultStylusIconId() = 0;
virtual PointerIconStyle getCustomPointerIconId() = 0;
- virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position) = 0;
};
/*
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index a63453d655e2..0baa9291f54d 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -129,7 +129,7 @@ void SpriteController::doUpdateSprites() {
update.state.surfaceVisible = false;
update.state.surfaceControl =
obtainSurface(update.state.surfaceWidth, update.state.surfaceHeight,
- update.state.displayId);
+ update.state.displayId, update.state.skipScreenshot);
if (update.state.surfaceControl != NULL) {
update.surfaceChanged = surfaceChanged = true;
}
@@ -209,7 +209,7 @@ void SpriteController::doUpdateSprites() {
(update.state.dirty &
(DIRTY_ALPHA | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER |
DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID | DIRTY_ICON_STYLE |
- DIRTY_DRAW_DROP_SHADOW))))) {
+ DIRTY_DRAW_DROP_SHADOW | DIRTY_SKIP_SCREENSHOT))))) {
needApplyTransaction = true;
if (wantSurfaceVisibleAndDrawn
@@ -260,6 +260,14 @@ void SpriteController::doUpdateSprites() {
t.setLayer(update.state.surfaceControl, surfaceLayer);
}
+ if (wantSurfaceVisibleAndDrawn &&
+ (becomingVisible || (update.state.dirty & DIRTY_SKIP_SCREENSHOT))) {
+ int32_t flags =
+ update.state.skipScreenshot ? ISurfaceComposerClient::eSkipScreenshot : 0;
+ t.setFlags(update.state.surfaceControl, flags,
+ ISurfaceComposerClient::eSkipScreenshot);
+ }
+
if (becomingVisible) {
t.show(update.state.surfaceControl);
@@ -332,8 +340,8 @@ void SpriteController::ensureSurfaceComposerClient() {
}
}
-sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height,
- int32_t displayId) {
+sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height, int32_t displayId,
+ bool hideOnMirrored) {
ensureSurfaceComposerClient();
const sp<SurfaceControl> parent = mParentSurfaceProvider(displayId);
@@ -341,11 +349,13 @@ sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height
ALOGE("Failed to get the parent surface for pointers on display %d", displayId);
}
+ int32_t createFlags = ISurfaceComposerClient::eHidden | ISurfaceComposerClient::eCursorWindow;
+ if (hideOnMirrored) {
+ createFlags |= ISurfaceComposerClient::eSkipScreenshot;
+ }
const sp<SurfaceControl> surfaceControl =
mSurfaceComposerClient->createSurface(String8("Sprite"), width, height,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eHidden |
- ISurfaceComposerClient::eCursorWindow,
+ PIXEL_FORMAT_RGBA_8888, createFlags,
parent ? parent->getHandle() : nullptr);
if (surfaceControl == nullptr || !surfaceControl->isValid()) {
ALOGE("Error creating sprite surface.");
@@ -474,6 +484,15 @@ void SpriteController::SpriteImpl::setDisplayId(int32_t displayId) {
}
}
+void SpriteController::SpriteImpl::setSkipScreenshot(bool skip) {
+ AutoMutex _l(mController.mLock);
+
+ if (mLocked.state.skipScreenshot != skip) {
+ mLocked.state.skipScreenshot = skip;
+ invalidateLocked(DIRTY_SKIP_SCREENSHOT);
+ }
+}
+
void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
bool wasDirty = mLocked.state.dirty;
mLocked.state.dirty |= dirty;
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 35776e9961b3..fdb15506fd0c 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -96,6 +96,10 @@ public:
/* Sets the id of the display where the sprite should be shown. */
virtual void setDisplayId(int32_t displayId) = 0;
+
+ /* Sets the flag to hide sprite on mirrored displays.
+ * This will add ISurfaceComposerClient::eSkipScreenshot flag to the sprite. */
+ virtual void setSkipScreenshot(bool skip) = 0;
};
/*
@@ -152,6 +156,7 @@ private:
DIRTY_DISPLAY_ID = 1 << 7,
DIRTY_ICON_STYLE = 1 << 8,
DIRTY_DRAW_DROP_SHADOW = 1 << 9,
+ DIRTY_SKIP_SCREENSHOT = 1 << 10,
};
/* Describes the state of a sprite.
@@ -160,28 +165,23 @@ private:
* on the sprites for a long time.
* Note that the SpriteIcon holds a reference to a shared (and immutable) bitmap. */
struct SpriteState {
- inline SpriteState() :
- dirty(0), visible(false),
- positionX(0), positionY(0), layer(0), alpha(1.0f), displayId(ADISPLAY_ID_DEFAULT),
- surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
- }
-
- uint32_t dirty;
+ uint32_t dirty{0};
SpriteIcon icon;
- bool visible;
- float positionX;
- float positionY;
- int32_t layer;
- float alpha;
+ bool visible{false};
+ float positionX{0};
+ float positionY{0};
+ int32_t layer{0};
+ float alpha{1.0f};
SpriteTransformationMatrix transformationMatrix;
- int32_t displayId;
+ int32_t displayId{ADISPLAY_ID_DEFAULT};
sp<SurfaceControl> surfaceControl;
- int32_t surfaceWidth;
- int32_t surfaceHeight;
- bool surfaceDrawn;
- bool surfaceVisible;
+ int32_t surfaceWidth{0};
+ int32_t surfaceHeight{0};
+ bool surfaceDrawn{false};
+ bool surfaceVisible{false};
+ bool skipScreenshot{false};
inline bool wantSurfaceVisible() const {
return visible && alpha > 0.0f && icon.isValid();
@@ -209,6 +209,7 @@ private:
virtual void setAlpha(float alpha);
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
virtual void setDisplayId(int32_t displayId);
+ virtual void setSkipScreenshot(bool skip);
inline const SpriteState& getStateLocked() const {
return mLocked.state;
@@ -272,7 +273,8 @@ private:
void doDisposeSurfaces();
void ensureSurfaceComposerClient();
- sp<SurfaceControl> obtainSurface(int32_t width, int32_t height, int32_t displayId);
+ sp<SurfaceControl> obtainSurface(int32_t width, int32_t height, int32_t displayId,
+ bool hideOnMirrored);
};
} // namespace android
diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp
index 99952aa14904..530d54129791 100644
--- a/libs/input/TouchSpotController.cpp
+++ b/libs/input/TouchSpotController.cpp
@@ -40,12 +40,13 @@ namespace android {
// --- Spot ---
void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float newX, float newY,
- int32_t displayId) {
+ int32_t displayId, bool skipScreenshot) {
sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
sprite->setAlpha(alpha);
sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
sprite->setPosition(newX, newY);
sprite->setDisplayId(displayId);
+ sprite->setSkipScreenshot(skipScreenshot);
x = newX;
y = newY;
@@ -84,7 +85,7 @@ TouchSpotController::~TouchSpotController() {
}
void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
- BitSet32 spotIdBits) {
+ BitSet32 spotIdBits, bool skipScreenshot) {
#if DEBUG_SPOT_UPDATES
ALOGD("setSpots: idBits=%08x", spotIdBits.value);
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
@@ -116,7 +117,7 @@ void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32
spot = createAndAddSpotLocked(id, mLocked.displaySpots);
}
- spot->updateSprite(&icon, x, y, mDisplayId);
+ spot->updateSprite(&icon, x, y, mDisplayId, skipScreenshot);
}
for (Spot* spot : mLocked.displaySpots) {
diff --git a/libs/input/TouchSpotController.h b/libs/input/TouchSpotController.h
index 5bbc75d9570b..608653c6a2e7 100644
--- a/libs/input/TouchSpotController.h
+++ b/libs/input/TouchSpotController.h
@@ -32,7 +32,7 @@ public:
TouchSpotController(int32_t displayId, PointerControllerContext& context);
~TouchSpotController();
void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
- BitSet32 spotIdBits);
+ BitSet32 spotIdBits, bool skipScreenshot);
void clearSpots();
void reloadSpotResources();
@@ -59,7 +59,8 @@ private:
y(0.0f),
mLastIcon(nullptr) {}
- void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId);
+ void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId,
+ bool skipScreenshot);
void dump(std::string& out, const char* prefix = "") const;
private:
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index a1bb5b3f1cc4..3bc0e24b6e2e 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <com_android_input_flags.h>
#include <flag_macros.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -30,8 +29,6 @@
namespace android {
-namespace input_flags = com::android::input::flags;
-
enum TestCursorType {
CURSOR_TYPE_DEFAULT = 0,
CURSOR_TYPE_HOVER,
@@ -64,11 +61,9 @@ public:
virtual PointerIconStyle getDefaultPointerIconId() override;
virtual PointerIconStyle getDefaultStylusIconId() override;
virtual PointerIconStyle getCustomPointerIconId() override;
- virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position) override;
bool allResourcesAreLoaded();
bool noResourcesAreLoaded();
- std::optional<int32_t> getLastReportedPointerDisplayId() { return latestPointerDisplayId; }
private:
void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
@@ -76,7 +71,6 @@ private:
bool pointerIconLoaded{false};
bool pointerResourcesLoaded{false};
bool additionalMouseResourcesLoaded{false};
- std::optional<int32_t /*displayId*/> latestPointerDisplayId;
};
void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
@@ -146,12 +140,6 @@ void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* ic
icon->hotSpotY = hotSpot.second;
}
-void MockPointerControllerPolicyInterface::onPointerDisplayIdChanged(int32_t displayId,
- const FloatPoint& /*position*/
-) {
- latestPointerDisplayId = displayId;
-}
-
class TestPointerController : public PointerController {
public:
TestPointerController(sp<android::gui::WindowInfosListener>& registeredListener,
@@ -159,7 +147,6 @@ public:
SpriteController& spriteController)
: PointerController(
policy, looper, spriteController,
- /*enabled=*/true,
[&registeredListener](const sp<android::gui::WindowInfosListener>& listener)
-> std::vector<gui::DisplayInfo> {
// Register listener
@@ -267,8 +254,7 @@ TEST_F(PointerControllerTest, useStylusTypeForStylusHover) {
mPointerController->reloadPointerResources();
}
-TEST_F_WITH_FLAGS(PointerControllerTest, setPresentationBeforeDisplayViewportDoesNotLoadResources,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(input_flags, enable_pointer_choreographer))) {
+TEST_F(PointerControllerTest, setPresentationBeforeDisplayViewportDoesNotLoadResources) {
// Setting the presentation mode before a display viewport is set will not load any resources.
mPointerController->setPresentation(PointerController::Presentation::POINTER);
ASSERT_TRUE(mPolicy->noResourcesAreLoaded());
@@ -278,26 +264,7 @@ TEST_F_WITH_FLAGS(PointerControllerTest, setPresentationBeforeDisplayViewportDoe
ASSERT_TRUE(mPolicy->allResourcesAreLoaded());
}
-TEST_F_WITH_FLAGS(PointerControllerTest, updatePointerIcon,
- REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(input_flags,
- enable_pointer_choreographer))) {
- ensureDisplayViewportIsSet();
- mPointerController->setPresentation(PointerController::Presentation::POINTER);
- mPointerController->unfade(PointerController::Transition::IMMEDIATE);
-
- int32_t type = CURSOR_TYPE_ADDITIONAL;
- std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
- EXPECT_CALL(*mPointerSprite, setVisible(true));
- EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
- EXPECT_CALL(*mPointerSprite,
- setIcon(AllOf(Field(&SpriteIcon::style, static_cast<PointerIconStyle>(type)),
- Field(&SpriteIcon::hotSpotX, hotspot.first),
- Field(&SpriteIcon::hotSpotY, hotspot.second))));
- mPointerController->updatePointerIcon(static_cast<PointerIconStyle>(type));
-}
-
-TEST_F_WITH_FLAGS(PointerControllerTest, updatePointerIconWithChoreographer,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(input_flags, enable_pointer_choreographer))) {
+TEST_F(PointerControllerTest, updatePointerIconWithChoreographer) {
// When PointerChoreographer is enabled, the presentation mode is set before the viewport.
mPointerController->setPresentation(PointerController::Presentation::POINTER);
ensureDisplayViewportIsSet();
@@ -348,28 +315,43 @@ TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
ensureDisplayViewportIsSet();
}
-TEST_F(PointerControllerTest, notifiesPolicyWhenPointerDisplayChanges) {
- EXPECT_FALSE(mPolicy->getLastReportedPointerDisplayId())
- << "A pointer display change does not occur when PointerController is created.";
-
- ensureDisplayViewportIsSet(ADISPLAY_ID_DEFAULT);
-
- const auto lastReportedPointerDisplayId = mPolicy->getLastReportedPointerDisplayId();
- ASSERT_TRUE(lastReportedPointerDisplayId)
- << "The policy is notified of a pointer display change when the viewport is first set.";
- EXPECT_EQ(ADISPLAY_ID_DEFAULT, *lastReportedPointerDisplayId)
- << "Incorrect pointer display notified.";
-
- ensureDisplayViewportIsSet(42);
-
- EXPECT_EQ(42, *mPolicy->getLastReportedPointerDisplayId())
- << "The policy is notified when the pointer display changes.";
-
- // Release the PointerController.
- mPointerController = nullptr;
+TEST_F(PointerControllerTest, updatesSkipScreenshotFlagForTouchSpots) {
+ ensureDisplayViewportIsSet();
- EXPECT_EQ(ADISPLAY_ID_NONE, *mPolicy->getLastReportedPointerDisplayId())
- << "The pointer display changes to invalid when PointerController is destroyed.";
+ PointerCoords testSpotCoords;
+ testSpotCoords.clear();
+ testSpotCoords.setAxisValue(AMOTION_EVENT_AXIS_X, 1);
+ testSpotCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
+ BitSet32 testIdBits;
+ testIdBits.markBit(0);
+ std::array<uint32_t, MAX_POINTER_ID + 1> testIdToIndex;
+
+ sp<MockSprite> testSpotSprite(new NiceMock<MockSprite>);
+
+ // By default sprite is not marked secure
+ EXPECT_CALL(*mSpriteController, createSprite).WillOnce(Return(testSpotSprite));
+ EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false));
+
+ // Update spots to sync state with sprite
+ mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
+ ADISPLAY_ID_DEFAULT);
+ testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
+
+ // Marking the display to skip screenshot should update sprite as well
+ mPointerController->setSkipScreenshot(ADISPLAY_ID_DEFAULT, true);
+ EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(true));
+
+ // Update spots to sync state with sprite
+ mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
+ ADISPLAY_ID_DEFAULT);
+ testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
+
+ // Reset flag and verify again
+ mPointerController->setSkipScreenshot(ADISPLAY_ID_DEFAULT, false);
+ EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false));
+ mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
+ ADISPLAY_ID_DEFAULT);
+ testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
}
class PointerControllerWindowInfoListenerTest : public Test {};
diff --git a/libs/input/tests/mocks/MockSprite.h b/libs/input/tests/mocks/MockSprite.h
index 013b79c3a3bf..0867221d9eed 100644
--- a/libs/input/tests/mocks/MockSprite.h
+++ b/libs/input/tests/mocks/MockSprite.h
@@ -34,6 +34,7 @@ public:
MOCK_METHOD(void, setAlpha, (float), (override));
MOCK_METHOD(void, setTransformationMatrix, (const SpriteTransformationMatrix&), (override));
MOCK_METHOD(void, setDisplayId, (int32_t), (override));
+ MOCK_METHOD(void, setSkipScreenshot, (bool), (override));
};
} // namespace android
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 554fe5efac3d..7ddf11e41a41 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -50,6 +50,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.media.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -984,37 +985,7 @@ public final class MediaRouter2 {
@SystemApi
@RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)
public void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
- mImpl.transfer(
- controller.getRoutingSessionInfo(),
- route,
- Process.myUserHandle(),
- mContext.getPackageName());
- }
-
- /**
- * Transfers the media of a routing controller to the given route.
- *
- * <p>This will be no-op for non-system media routers.
- *
- * @param controller a routing controller controlling media routing.
- * @param route the route you want to transfer the media to.
- * @param transferInitiatorUserHandle the user handle of the app that initiated the transfer
- * request.
- * @param transferInitiatorPackageName the package name of the app that initiated the transfer.
- * This value is used with the user handle to populate {@link
- * RoutingController#wasTransferInitiatedBySelf()}.
- * @hide
- */
- public void transfer(
- @NonNull RoutingController controller,
- @NonNull MediaRoute2Info route,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName) {
- mImpl.transfer(
- controller.getRoutingSessionInfo(),
- route,
- transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ mImpl.transfer(controller.getRoutingSessionInfo(), route);
}
void requestCreateController(
@@ -1913,13 +1884,7 @@ public final class MediaRouter2 {
*/
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
public boolean wasTransferInitiatedBySelf() {
- RoutingSessionInfo sessionInfo = getRoutingSessionInfo();
-
- UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle();
- String transferInitiatorPackageName = sessionInfo.getTransferInitiatorPackageName();
-
- return Objects.equals(Process.myUserHandle(), transferInitiatorUserHandle)
- && Objects.equals(mContext.getPackageName(), transferInitiatorPackageName);
+ return mImpl.wasTransferredBySelf(getRoutingSessionInfo());
}
/**
@@ -2064,24 +2029,47 @@ public final class MediaRouter2 {
}
/**
- * Transfers to a given route for the remote session. The given route must be included in
- * {@link RoutingSessionInfo#getTransferableRoutes()}.
+ * Attempts a transfer to a {@link RoutingSessionInfo#getTransferableRoutes() transferable
+ * route}.
+ *
+ * <p>Transferring to a transferable route does not require the app to transfer the playback
+ * state from one route to the other. The route provider completely manages the transfer. An
+ * example of provider-managed transfers are the switches between the system's routes, like
+ * the built-in speakers and a BT headset.
*
+ * @return True if the transfer is handled by this controller, or false if a new controller
+ * should be created instead.
* @see RoutingSessionInfo#getSelectedRoutes()
* @see RoutingSessionInfo#getTransferableRoutes()
* @see ControllerCallback#onControllerUpdated
*/
- void transferToRoute(@NonNull MediaRoute2Info route) {
+ boolean tryTransferWithinProvider(@NonNull MediaRoute2Info route) {
Objects.requireNonNull(route, "route must not be null");
synchronized (mControllerLock) {
if (isReleased()) {
- Log.w(TAG, "transferToRoute: Called on released controller. Ignoring.");
- return;
+ Log.w(
+ TAG,
+ "tryTransferWithinProvider: Called on released controller. Ignoring.");
+ return true;
}
- if (!mSessionInfo.getTransferableRoutes().contains(route.getId())) {
- Log.w(TAG, "Ignoring transferring to a non-transferable route=" + route);
- return;
+ // If this call is trying to transfer to a selected system route, we let them
+ // through as a provider driven transfer in order to update the transfer reason and
+ // initiator data.
+ boolean isSystemRouteReselection =
+ Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()
+ && mSessionInfo.isSystemSession()
+ && route.isSystemRoute()
+ && mSessionInfo.getSelectedRoutes().contains(route.getId());
+ if (!isSystemRouteReselection
+ && !mSessionInfo.getTransferableRoutes().contains(route.getId())) {
+ Log.i(
+ TAG,
+ "Transferring to a non-transferable route="
+ + route
+ + " session= "
+ + mSessionInfo.getId());
+ return false;
}
}
@@ -2096,6 +2084,7 @@ public final class MediaRouter2 {
Log.e(TAG, "Unable to transfer to route for session.", ex);
}
}
+ return true;
}
/**
@@ -2490,11 +2479,7 @@ public final class MediaRouter2 {
void stop();
- void transfer(
- @NonNull RoutingSessionInfo sessionInfo,
- @NonNull MediaRoute2Info route,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName);
+ void transfer(@NonNull RoutingSessionInfo sessionInfo, @NonNull MediaRoute2Info route);
List<RoutingController> getControllers();
@@ -2515,6 +2500,11 @@ public final class MediaRouter2 {
boolean shouldNotifyStop,
RoutingController controller);
+ /**
+ * Returns the value of {@link RoutingController#wasTransferInitiatedBySelf()} for the app
+ * associated with this router.
+ */
+ boolean wasTransferredBySelf(RoutingSessionInfo sessionInfo);
}
/**
@@ -2715,7 +2705,7 @@ public final class MediaRouter2 {
List<RoutingSessionInfo> sessionInfos = getRoutingSessions();
RoutingSessionInfo targetSession = sessionInfos.get(sessionInfos.size() - 1);
- transfer(targetSession, route, mClientUser, mContext.getPackageName());
+ transfer(targetSession, route);
}
@Override
@@ -2738,24 +2728,15 @@ public final class MediaRouter2 {
*
* @param sessionInfo The {@link RoutingSessionInfo routing session} to transfer.
* @param route The {@link MediaRoute2Info route} to transfer to.
- * @param transferInitiatorUserHandle The user handle of the app that initiated the
- * transfer.
- * @param transferInitiatorPackageName The package name if of the app that initiated the
- * transfer.
* @see #transferToRoute(RoutingSessionInfo, MediaRoute2Info, UserHandle, String)
* @see #requestCreateSession(RoutingSessionInfo, MediaRoute2Info)
*/
@Override
@SuppressWarnings("AndroidFrameworkRequiresPermission")
public void transfer(
- @NonNull RoutingSessionInfo sessionInfo,
- @NonNull MediaRoute2Info route,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName) {
+ @NonNull RoutingSessionInfo sessionInfo, @NonNull MediaRoute2Info route) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
Objects.requireNonNull(route, "route must not be null");
- Objects.requireNonNull(transferInitiatorUserHandle);
- Objects.requireNonNull(transferInitiatorPackageName);
Log.v(
TAG,
@@ -2772,15 +2753,19 @@ public final class MediaRouter2 {
return;
}
- if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
- transferToRoute(
- sessionInfo,
- route,
- transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ // If this call is trying to transfer to a selected system route, we let them
+ // through as a provider driven transfer in order to update the transfer reason and
+ // initiator data.
+ boolean isSystemRouteReselection =
+ Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()
+ && sessionInfo.isSystemSession()
+ && route.isSystemRoute()
+ && sessionInfo.getSelectedRoutes().contains(route.getId());
+ if (sessionInfo.getTransferableRoutes().contains(route.getId())
+ || isSystemRouteReselection) {
+ transferToRoute(sessionInfo, route, mClientUser, mClientPackageName);
} else {
- requestCreateSession(sessionInfo, route, transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ requestCreateSession(sessionInfo, route, mClientUser, mClientPackageName);
}
}
@@ -3035,6 +3020,14 @@ public final class MediaRouter2 {
releaseSession(controller.getRoutingSessionInfo());
}
+ @Override
+ public boolean wasTransferredBySelf(RoutingSessionInfo sessionInfo) {
+ UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle();
+ String transferInitiatorPackageName = sessionInfo.getTransferInitiatorPackageName();
+ return Objects.equals(mClientUser, transferInitiatorUserHandle)
+ && Objects.equals(mClientPackageName, transferInitiatorPackageName);
+ }
+
/**
* Retrieves the system session info for the given package.
*
@@ -3587,20 +3580,14 @@ public final class MediaRouter2 {
}
RoutingController controller = getCurrentController();
- if (controller
- .getRoutingSessionInfo()
- .getTransferableRoutes()
- .contains(route.getId())) {
- controller.transferToRoute(route);
- return;
+ if (!controller.tryTransferWithinProvider(route)) {
+ requestCreateController(
+ controller,
+ route,
+ MANAGER_REQUEST_ID_NONE,
+ Process.myUserHandle(),
+ mContext.getPackageName());
}
-
- requestCreateController(
- controller,
- route,
- MANAGER_REQUEST_ID_NONE,
- Process.myUserHandle(),
- mContext.getPackageName());
}
@Override
@@ -3617,10 +3604,7 @@ public final class MediaRouter2 {
*/
@Override
public void transfer(
- @NonNull RoutingSessionInfo sessionInfo,
- @NonNull MediaRoute2Info route,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName) {
+ @NonNull RoutingSessionInfo sessionInfo, @NonNull MediaRoute2Info route) {
// Do nothing.
}
@@ -3739,6 +3723,14 @@ public final class MediaRouter2 {
}
}
+ @Override
+ public boolean wasTransferredBySelf(RoutingSessionInfo sessionInfo) {
+ UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle();
+ String transferInitiatorPackageName = sessionInfo.getTransferInitiatorPackageName();
+ return Objects.equals(Process.myUserHandle(), transferInitiatorUserHandle)
+ && Objects.equals(mContext.getPackageName(), transferInitiatorPackageName);
+ }
+
@GuardedBy("mLock")
private void registerRouterStubIfNeededLocked() throws RemoteException {
if (mStub == null) {
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index 58f56b873246..78a53578f5ca 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "PerformanceHintNativeTest"
+#include <aidl/android/hardware/power/ChannelConfig.h>
#include <aidl/android/hardware/power/SessionConfig.h>
#include <aidl/android/hardware/power/SessionTag.h>
#include <aidl/android/hardware/power/WorkDuration.h>
@@ -54,6 +55,9 @@ public:
MOCK_METHOD(ScopedAStatus, getHintSessionThreadIds,
(const std::shared_ptr<IHintSession>& hintSession, ::std::vector<int32_t>* tids),
(override));
+ MOCK_METHOD(ScopedAStatus, getSessionChannel,
+ (const ::ndk::SpAIBinder& in_token, hal::ChannelConfig* _aidl_return), (override));
+ MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override));
MOCK_METHOD(SpAIBinder, asBinder, (), (override));
MOCK_METHOD(bool, isRemote, (), (override));
};
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index de9eada18104..2fe2ce39813b 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -1212,16 +1212,16 @@ public final class CardEmulation {
*
* @param service The ComponentName of the service
* @param status true to enable, false to disable
+ * @param userId the user handle of the user whose information is being requested.
* @return set service for the category and true if service is already set return false.
*
* @hide
*/
- public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status) {
+ public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status,
+ int userId) {
if (service == null) {
throw new NullPointerException("activity or service or category is null");
}
- int userId = mContext.getUser().getIdentifier();
-
try {
return sService.setServiceEnabledForCategoryOther(userId, service, status);
} catch (RemoteException e) {
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java
index b52faba79ed7..4c76fb02f7d8 100644
--- a/nfc/java/android/nfc/cardemulation/PollingFrame.java
+++ b/nfc/java/android/nfc/cardemulation/PollingFrame.java
@@ -44,8 +44,15 @@ public final class PollingFrame implements Parcelable{
/**
* @hide
*/
- @IntDef(prefix = { "POLLING_LOOP_TYPE_"}, value = { POLLING_LOOP_TYPE_A, POLLING_LOOP_TYPE_B,
- POLLING_LOOP_TYPE_F, POLLING_LOOP_TYPE_OFF, POLLING_LOOP_TYPE_ON })
+ @IntDef(prefix = { "POLLING_LOOP_TYPE_"},
+ value = {
+ POLLING_LOOP_TYPE_A,
+ POLLING_LOOP_TYPE_B,
+ POLLING_LOOP_TYPE_F,
+ POLLING_LOOP_TYPE_OFF,
+ POLLING_LOOP_TYPE_ON,
+ POLLING_LOOP_TYPE_UNKNOWN
+ })
@Retention(RetentionPolicy.SOURCE)
@FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
public @interface PollingFrameType {}
diff --git a/packages/CarrierDefaultApp/res/values-fa/strings.xml b/packages/CarrierDefaultApp/res/values-fa/strings.xml
index abf47fbfe2cd..d9afe873b444 100644
--- a/packages/CarrierDefaultApp/res/values-fa/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fa/strings.xml
@@ -17,7 +17,7 @@
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"تقویت‌کننده عملکرد"</string>
<string name="performance_boost_notification_title" msgid="3126203390685781861">"گزینه‌های نسل پنجم شرکت مخابراتی شما"</string>
<string name="performance_boost_notification_detail" msgid="216569851036236346">"‏برای دیدن گزینه‌های مرتبط با تجربه برنامه، به وب‌سایت %s مراجعه کنید"</string>
- <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"اکنون نه"</string>
+ <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"حالا نه"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"مدیریت"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"تقویت‌کننده عملکرد خریداری کنید."</string>
</resources>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
index b239fc35d41e..8617c6a28f43 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -20,7 +20,7 @@
<string name="app_name" msgid="4539824758261855508">"Gestionnaire d\'identifiants"</string>
<string name="string_cancel" msgid="6369133483981306063">"Annuler"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuer"</string>
- <string name="string_more_options" msgid="2763852250269945472">"Autre façon"</string>
+ <string name="string_more_options" msgid="2763852250269945472">"Autre option"</string>
<string name="string_learn_more" msgid="4541600451688392447">"En savoir plus"</string>
<string name="content_description_show_password" msgid="3283502010388521607">"Afficher le mot de passe"</string>
<string name="content_description_hide_password" msgid="6841375971631767996">"Masquer le mot de passe"</string>
@@ -40,7 +40,7 @@
<string name="choose_provider_title" msgid="8870795677024868108">"Choisissez où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos informations et vous connecter plus rapidement la prochaine fois"</string>
<string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Créer une clé d\'accès pour se connecter à <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
- <string name="choose_create_option_password_title" msgid="4481366993598649224">"Enregistrer un mot de passe pour se connecter à <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
+ <string name="choose_create_option_password_title" msgid="4481366993598649224">"Enregistrer le mot de passe pour se connecter à <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
<string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Enregistrer les informations de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
<string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
<string name="password" msgid="6738570945182936667">"mot de passe"</string>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index 868357f6b42c..3ec7da3721e8 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -28,7 +28,7 @@
<string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Անցաբառերի շնորհիվ դուք բարդ գաղտնաբառեր ստեղծելու կամ հիշելու անհրաժեշտություն չեք ունենա"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Անցաբառերը գաղտնագրված թվային բանալիներ են, որոնք ստեղծվում են մատնահետքի, դեմքով ապակողպման կամ էկրանի կողպման օգտագործմամբ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Դուք կարող եք մուտք գործել այլ սարքերում, քանի որ մուտքի բանալիները պահվում են գաղտնաբառերի կառավարիչում"</string>
- <string name="more_about_passkeys_title" msgid="7797903098728837795">"Ավելին՝ անցաբառերի մասին"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Ավելին՝ մուտքի բանալիների մասին"</string>
<string name="passwordless_technology_title" msgid="2497513482056606668">"Գաղտնաբառեր չպահանջող տեխնոլոգիա"</string>
<string name="passwordless_technology_detail" msgid="6853928846532955882">"Մուտքի բանալիները ձեզ թույլ են տալիս մուտք գործել առանց գաղտնաբառերի։ Ձեզ պարզապես հարկավոր է օգտագործել ձեր մատնահետքը, դիմաճանաչումը, PIN կոդը կամ նախշը՝ ձեր ինքնությունը հաստատելու և մուտքի բանալի ստեղծելու համար։"</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"Բաց բանալու կրիպտոգրաֆիա"</string>
@@ -36,7 +36,7 @@
<string name="improved_account_security_title" msgid="1069841917893513424">"Հաշվի բարելավված անվտանգություն"</string>
<string name="improved_account_security_detail" msgid="9123750251551844860">"Յուրաքանչյուր բանալի բացառապես կապված է հավելվածի կամ կայքի հետ, որի համար այն ստեղծվել է, ուստի դուք երբեք չեք կարող սխալմամբ մուտք գործել կեղծ հավելված կամ կայք։ Բացի այդ՝ սերվերներում պահվում են միայն բաց բանալիներ, ինչը զգալիորեն դժվարացնում է կոտրումը։"</string>
<string name="seamless_transition_title" msgid="5335622196351371961">"Սահուն անցում"</string>
- <string name="seamless_transition_detail" msgid="4475509237171739843">"Թեև մենք առանց գաղտնաբառերի ապագայի ճանապարհին ենք, դրանք դեռ հասանելի կլինեն անցաբառերի հետ մեկտեղ։"</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Թեև մենք առանց գաղտնաբառերի ապագայի ճանապարհին ենք, դրանք դեռ հասանելի կլինեն մուտքի բանալիների հետ մեկտեղ։"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Նշեք, թե որտեղ եք ուզում պահել ձեր <xliff:g id="CREATETYPES">%1$s</xliff:g>ը"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Ընտրեք գաղտնաբառերի կառավարիչ՝ ձեր տեղեկությունները պահելու և հաջորդ անգամ ավելի արագ մուտք գործելու համար"</string>
<string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Ստեղծե՞լ մուտքի բանալի՝ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելված մուտք գործելու համար"</string>
@@ -44,7 +44,7 @@
<string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Պահե՞լ «<xliff:g id="APP_NAME">%1$s</xliff:g>» հավելվածի մուտքի տվյալները"</string>
<string name="passkey" msgid="632353688396759522">"մուտքի բանալի"</string>
<string name="password" msgid="6738570945182936667">"գաղտնաբառ"</string>
- <string name="passkeys" msgid="5733880786866559847">"անցաբառեր"</string>
+ <string name="passkeys" msgid="5733880786866559847">"մուտքի բանալիներ"</string>
<string name="passwords" msgid="5419394230391253816">"գաղտնաբառեր"</string>
<string name="sign_ins" msgid="4710739369149469208">"մուտք"</string>
<string name="sign_in_info" msgid="2627704710674232328">"մուտքի տվյալներ"</string>
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 46a51389214f..0bae63a1c525 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -24,7 +24,7 @@
<string name="string_cancel">Cancel</string>
<!-- This is a label for a button that takes user to the next screen. [CHAR LIMIT=20] -->
<string name="string_continue">Continue</string>
- <!-- This is a label for a button that leads to a holistic view of all different options where the user can save their new app credential. [CHAR LIMIT=20] -->
+ <!-- This is a label for a button that leads to a holistic view of all different options where the user can save their new app credential. [CHAR LIMIT=30] -->
<string name="string_more_options">Save another way</string>
<!-- This is a label for a button that links to additional information about passkeys. [CHAR LIMIT=20] -->
<string name="string_learn_more">Learn more</string>
@@ -174,4 +174,4 @@
<!-- Text shown in the dropdown presentation to select more sign in options. [CHAR LIMIT=120] -->
<string name="dropdown_presentation_more_sign_in_options_text">Sign-in options</string>
<string name="more_options_content_description">More</string>
-</resources> \ No newline at end of file
+</resources>
diff --git a/packages/CredentialManager/res/xml/autofill_service_configuration.xml b/packages/CredentialManager/res/xml/autofill_service_configuration.xml
index 25cc094fa44e..0151add1c8e8 100644
--- a/packages/CredentialManager/res/xml/autofill_service_configuration.xml
+++ b/packages/CredentialManager/res/xml/autofill_service_configuration.xml
@@ -5,6 +5,6 @@
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
-<autofill-service-configuration
+<autofill-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:supportsInlineSuggestions="true"/> \ No newline at end of file
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 9a8bd375d809..16f64379be41 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ሞንጎሊያኛ"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ጂዮርጂያኛ"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ታይላንድኛ (ኬድማኒ)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ታይላንድኛ (ፓታሾት)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-as/strings.xml b/packages/InputDevices/res/values-as/strings.xml
index 802b13eacfe8..c57b59190f6c 100644
--- a/packages/InputDevices/res/values-as/strings.xml
+++ b/packages/InputDevices/res/values-as/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"থাই (কেডমানি)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"থাই (পাটাচ’টে)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml
index 4a8e7ff7092e..9c6bdb3925b9 100644
--- a/packages/InputDevices/res/values-az/strings.xml
+++ b/packages/InputDevices/res/values-az/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Monqol"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gürcü"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tay (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tay (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml
index 4dd59bf70716..c5aa66f4e273 100644
--- a/packages/InputDevices/res/values-be/strings.xml
+++ b/packages/InputDevices/res/values-be/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Мангольская"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Грузінская"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Тайская (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Тайская (Патачотэ)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index 3dbd6f735644..1260d6af08c2 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"монголски"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"грузински"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"тайландски (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"тайландски (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bn/strings.xml b/packages/InputDevices/res/values-bn/strings.xml
index 0d8e5d855409..a038da9eb4d0 100644
--- a/packages/InputDevices/res/values-bn/strings.xml
+++ b/packages/InputDevices/res/values-bn/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"মঙ্গোলিয়ান"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"জর্জিয়ান"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"থাই (কেডমানি)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"থাই (পাট্টাচোটে)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 7832e6eb215f..9ee17e106729 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolština"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruzínština"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"thajština (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"thajština (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index c4de5a8817e6..3db695e72763 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolisch"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgisch"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thailändisch (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thailändisch (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 216e91fa97be..7490f7d546bd 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tailandés (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tailandés (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index 4fba26d8ecea..11280dd26c9a 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"مغولی"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"گرجستانی"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"تایلندی (کدمانی)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"تایلندی (پاتاچوته)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index f375dadb400d..5c931cf178dd 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Géorgien"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thaï (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thaï (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index 3fa45b13a5a1..7e3df8200b1e 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"मंगोलियन"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"जॉर्जियन कीबोर्ड का लेआउट"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"थाई (केडमेनी)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"थाई (पटैचोटे)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 409a32154613..ba3dc51a4543 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolski"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruzijska"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"tajlandski (kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tajski (pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index 740cf376db3f..eed8316c5af1 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolo"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thai (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thai (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 6badc3f8b0e4..8cfe2cbf3e79 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"מונגולית"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"גיאורגית"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"‏תאית (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"‏תאית (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 967688644697..d1b334b0f45a 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"モンゴル語"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ジョージア語"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"タイ語(Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"タイ語(Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml
index 93735c9c2af3..8928f684b8b6 100644
--- a/packages/InputDevices/res/values-ka/strings.xml
+++ b/packages/InputDevices/res/values-ka/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"მონღოლური"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ქართული"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ტაილანდური (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ტაილანდური (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-km/strings.xml b/packages/InputDevices/res/values-km/strings.xml
index 0f3832e013b4..53eb6f53fbea 100644
--- a/packages/InputDevices/res/values-km/strings.xml
+++ b/packages/InputDevices/res/values-km/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"មុងហ្គោលី"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ហ្សក​ហ្ស៊ី"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ថៃ (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ថៃ (ប៉ាតាឈោត)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml
index 96b92946ab22..c743a6e1c65f 100644
--- a/packages/InputDevices/res/values-kn/strings.xml
+++ b/packages/InputDevices/res/values-kn/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ಮಂಗೋಲಿಯನ್"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ಜಾರ್ಜಿಯನ್"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ಥಾಯ್ (ಕೆಡ್‍ಮನೀ)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ಥಾಯ್ (ಪಟ್ಟಚೋಟ್)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index 9956f26ec93f..0e375dd743f3 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"몽골어"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"조지아어"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"태국어(Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"태국어(Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-mk/strings.xml b/packages/InputDevices/res/values-mk/strings.xml
index 27096895a52d..4e8be4637ea5 100644
--- a/packages/InputDevices/res/values-mk/strings.xml
+++ b/packages/InputDevices/res/values-mk/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"монголски"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"грузиски"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"тајландски (кедмани)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"тајландски (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml
index 94ec21acf3dd..9e4c19098af8 100644
--- a/packages/InputDevices/res/values-ms/strings.xml
+++ b/packages/InputDevices/res/values-ms/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Bahasa Mongolia"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Bahasa Georgia"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thai (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thai (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index 1d399ae4d07a..d28ee9b19157 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongools"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgisch"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thai (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thai (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-or/strings.xml b/packages/InputDevices/res/values-or/strings.xml
index 0d0fbafe3424..e92c15566dc4 100644
--- a/packages/InputDevices/res/values-or/strings.xml
+++ b/packages/InputDevices/res/values-or/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ମଙ୍ଗୋଲିଆନ୍"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ଜର୍ଜିଆନ୍"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ଥାଇ (କେଡମାନି)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ଥାଇ (ପାଟ୍ଟାଚୋଟେ)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml
index e2bad4fee77d..4a0c3be58def 100644
--- a/packages/InputDevices/res/values-pt-rBR/strings.xml
+++ b/packages/InputDevices/res/values-pt-rBR/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tailandês (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tailandês (pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 7ade82f54d8f..c54b620ee6fd 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tailandês (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tailandês (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index e2bad4fee77d..4a0c3be58def 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tailandês (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tailandês (pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml
index 27b031bcc440..97aed6286a8c 100644
--- a/packages/InputDevices/res/values-si/strings.xml
+++ b/packages/InputDevices/res/values-si/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"මොන්ගෝලියානු"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ජෝර්ජියානු"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"තායි (කෙඩ්මනී)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"තායි (පට්ටචෝටේ)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index f29b6655f587..3d08415081fe 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongoliska"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"georgiska"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thai (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"thailändska (pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index ade2c284cf8d..42714a55530f 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Kimongolia"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Kijojia"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Kithai (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Kitai (Kipatachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ta/strings.xml b/packages/InputDevices/res/values-ta/strings.xml
index 14a17adaac26..f8bc751c3ca5 100644
--- a/packages/InputDevices/res/values-ta/strings.xml
+++ b/packages/InputDevices/res/values-ta/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"மங்கோலியன்"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ஜார்ஜியன்"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"தாய் (கேட்மேனி)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"தாய் (பட்டாசொட்டே)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml
index 676dd924d601..2c1c1f8021fa 100644
--- a/packages/InputDevices/res/values-te/strings.xml
+++ b/packages/InputDevices/res/values-te/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"మంగోలియన్"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"జార్జియన్"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"థాయ్ (కెడ్మనీ)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"థాయ్ (పత్తచోత్)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 247312836ae4..3b96226bbe81 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ภาษามองโกเลีย"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"ภาษาจอร์เจีย"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ไทย (เกษมณี)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ไทย (ปัตตะโชติ)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index ba4703c0a9df..a5c89d746b58 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Moğolca"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gürcüce"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tayca (Kedmanee)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tayca (Pattachote)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index c74b1c13d5bc..dd3aab8c2aac 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -51,6 +51,5 @@
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Монгольська"</string>
<string name="keyboard_layout_georgian" msgid="4596185456863747454">"Грузинська"</string>
<string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Тайська (кедмані)"</string>
- <!-- no translation found for keyboard_layout_thai_pattachote (2547992342794252205) -->
- <skip />
+ <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Тайська (паттачоте)"</string>
</resources>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
index eef21991b845..c96644ca8920 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
@@ -23,23 +23,23 @@ import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
-import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
-
import androidx.annotation.Nullable;
/**
* Installation failed: Return status code to the caller or display failure UI to user
*/
public class InstallFailed extends Activity {
+
private static final String LOG_TAG = InstallFailed.class.getSimpleName();
- /** Label of the app that failed to install */
+ /**
+ * Label of the app that failed to install
+ */
private CharSequence mLabel;
private AlertDialog mDialog;
@@ -80,29 +80,29 @@ public class InstallFailed extends Activity {
setFinishOnTouchOutside(true);
- int statusCode = getIntent().getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
+ Intent intent = getIntent();
+ int statusCode = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ boolean returnResult = intent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false);
- if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
- int legacyStatus = getIntent().getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS,
- PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ if (returnResult) {
+ int legacyStatus = intent.getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS,
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
// Return result if requested
Intent result = new Intent();
result.putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus);
setResult(Activity.RESULT_FIRST_USER, result);
finish();
- } else {
- Intent intent = getIntent();
- ApplicationInfo appInfo = intent
- .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
- Uri packageURI = intent.getData();
+ } else if (statusCode != PackageInstaller.STATUS_FAILURE_ABORTED) {
+ // statusCode will be STATUS_FAILURE_ABORTED if the update-owner confirmation dialog was
+ // dismissed by the user. We don't want to show a InstallFailed dialog in this case.
+ // If the user denies install permission for normal installs, this dialog will never be
+ // triggered as the status code is returned from PackageInstallerActivity.java
// Set header icon and title
- PackageUtil.AppSnippet as;
- PackageManager pm = getPackageManager();
- as = intent.getParcelableExtra(PackageInstallerActivity.EXTRA_APP_SNIPPET,
- PackageUtil.AppSnippet.class);
+ PackageUtil.AppSnippet as = intent.getParcelableExtra(
+ PackageInstallerActivity.EXTRA_APP_SNIPPET, PackageUtil.AppSnippet.class);
// Store label for dialog
mLabel = as.label;
@@ -127,6 +127,8 @@ public class InstallFailed extends Activity {
// Get status messages
setExplanationFromErrorCode(statusCode);
+ } else {
+ finish();
}
}
@@ -135,6 +137,7 @@ public class InstallFailed extends Activity {
* "manage applications" settings page.
*/
public static class OutOfSpaceDialog extends DialogFragment {
+
private InstallFailed mActivity;
@Override
@@ -147,16 +150,16 @@ public class InstallFailed extends Activity {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(mActivity)
- .setTitle(R.string.out_of_space_dlg_title)
- .setMessage(getString(R.string.out_of_space_dlg_text, mActivity.mLabel))
- .setPositiveButton(R.string.manage_applications, (dialog, which) -> {
- // launch manage applications
- Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
- startActivity(intent);
- mActivity.finish();
- })
- .setNegativeButton(R.string.cancel, (dialog, which) -> mActivity.finish())
- .create();
+ .setTitle(R.string.out_of_space_dlg_title)
+ .setMessage(getString(R.string.out_of_space_dlg_text, mActivity.mLabel))
+ .setPositiveButton(R.string.manage_applications, (dialog, which) -> {
+ // launch manage applications
+ Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
+ startActivity(intent);
+ mActivity.finish();
+ })
+ .setNegativeButton(R.string.cancel, (dialog, which) -> mActivity.finish())
+ .create();
}
@Override
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index 1a6c2bb2ec18..59a511db5b3a 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -30,6 +30,8 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -91,8 +93,11 @@ public class InstallInstalling extends Activity {
// ContentResolver.SCHEME_FILE
// STAGED_SESSION_ID extra contains an ID of a previously staged install session.
final File sourceFile = new File(mPackageURI.getPath());
- PackageUtil.AppSnippet as = getIntent()
- .getParcelableExtra(EXTRA_APP_SNIPPET, PackageUtil.AppSnippet.class);
+
+ // Dialogs displayed while changing update-owner have a blank icon. To fix this,
+ // fetch the appSnippet from the source file again
+ PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
+ getIntent().putExtra(EXTRA_APP_SNIPPET, as);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@@ -244,6 +249,14 @@ public class InstallInstalling extends Activity {
super.onDestroy();
}
+ @Override
+ public void finish() {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
+ super.finish();
+ }
+
/**
* Launch the appropriate finish activity (success or failed) for the installation result.
*
@@ -299,7 +312,11 @@ public class InstallInstalling extends Activity {
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
try {
- session.commit(pendingIntent.getIntentSender());
+ // Delay committing the session by 100ms to fix a UI glitch while displaying the
+ // Update-Owner change dialog on top of the Installing dialog
+ new Handler(Looper.getMainLooper()).postDelayed(() -> {
+ session.commit(pendingIntent.getIntentSender());
+ }, 100);
} catch (Exception e) {
Log.e(LOG_TAG, "Cannot install package: ", e);
launchFailure(PackageInstaller.STATUS_FAILURE,
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
index cf2f85ed5356..13251d8da109 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
@@ -165,7 +165,9 @@ public class InstallStaging extends Activity {
if (mStagingTask != null) {
mStagingTask.cancel(true);
}
-
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
super.onDestroy();
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index a4c6ac7d95c7..3fea5996e3ef 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -193,6 +193,7 @@ public class InstallStart extends Activity {
if (isSessionInstall) {
nextActivity.setClass(this, PackageInstallerActivity.class);
+ nextActivity.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
} else {
Uri packageUri = intent.getData();
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 8bed945af32c..e0398aa49dc9 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -176,11 +176,14 @@ public class PackageInstallerActivity extends Activity {
}
private CharSequence getExistingUpdateOwnerLabel() {
+ return getApplicationLabel(getExistingUpdateOwner());
+ }
+
+ private String getExistingUpdateOwner() {
try {
final String packageName = mPkgInfo.packageName;
final InstallSourceInfo sourceInfo = mPm.getInstallSourceInfo(packageName);
- final String existingUpdateOwner = sourceInfo.getUpdateOwnerPackageName();
- return getApplicationLabel(existingUpdateOwner);
+ return sourceInfo.getUpdateOwnerPackageName();
} catch (NameNotFoundException e) {
return null;
}
@@ -299,6 +302,18 @@ public class PackageInstallerActivity extends Activity {
}
private void initiateInstall() {
+ final String existingUpdateOwner = getExistingUpdateOwner();
+ if (mSessionId == SessionInfo.INVALID_ID &&
+ !TextUtils.isEmpty(existingUpdateOwner) &&
+ !TextUtils.equals(existingUpdateOwner, mOriginatingPackage)) {
+ // Since update ownership is being changed, the system will request another
+ // user confirmation shortly. Thus, we don't need to ask the user to confirm
+ // installation here.
+ startInstall();
+ return;
+ }
+
+ // Proceed with user confirmation as we are not changing the update-owner in this install.
String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
@@ -465,10 +480,13 @@ public class PackageInstallerActivity extends Activity {
@Override
protected void onDestroy() {
- super.onDestroy();
while (!mActiveUnknownSourcesListeners.isEmpty()) {
unregister(mActiveUnknownSourcesListeners.get(0));
}
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
+ super.onDestroy();
}
private void bindUi() {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
index f7752ffad899..d969d1cf0a80 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
@@ -420,25 +420,48 @@ class InstallRepository(private val context: Context) {
* * If AppOP is granted and user action is required to proceed with install
* * If AppOp grant is to be requested from the user
*/
- fun requestUserConfirmation(): InstallStage {
+ fun requestUserConfirmation(): InstallStage? {
return if (isTrustedSource) {
if (localLogv) {
Log.i(LOG_TAG, "Install allowed")
}
- // Returns InstallUserActionRequired stage if install details could be successfully
- // computed, else it returns InstallAborted.
- generateConfirmationSnippet()
+ maybeDeferUserConfirmation()
} else {
val unknownSourceStage = handleUnknownSources(appOpRequestInfo)
if (unknownSourceStage.stageCode == InstallStage.STAGE_READY) {
// Source app already has appOp granted.
- generateConfirmationSnippet()
+ maybeDeferUserConfirmation()
} else {
unknownSourceStage
}
}
}
+ /**
+ * If the update-owner for the incoming app is being changed, defer confirming with the
+ * user and directly proceed with the install. The system will request another
+ * user confirmation shortly.
+ */
+ private fun maybeDeferUserConfirmation(): InstallStage? {
+ // Returns InstallUserActionRequired stage if install details could be successfully
+ // computed, else it returns InstallAborted.
+ val confirmationSnippet: InstallStage = generateConfirmationSnippet()
+
+ val existingUpdateOwner: CharSequence? = getExistingUpdateOwner(newPackageInfo!!)
+ return if (sessionId == SessionInfo.INVALID_ID &&
+ !TextUtils.isEmpty(existingUpdateOwner) &&
+ !TextUtils.equals(existingUpdateOwner, callingPackage)
+ ) {
+ // Since update ownership is being changed, the system will request another
+ // user confirmation shortly. Thus, we don't need to ask the user to confirm
+ // installation here.
+ initiateInstall()
+ null
+ } else {
+ confirmationSnippet
+ }
+ }
+
private fun generateConfirmationSnippet(): InstallStage {
val packageSource: Any?
val pendingUserActionReason: Int
@@ -639,11 +662,14 @@ class InstallRepository(private val context: Context) {
}
private fun getExistingUpdateOwnerLabel(pkgInfo: PackageInfo): CharSequence? {
+ return getApplicationLabel(getExistingUpdateOwner(pkgInfo))
+ }
+
+ private fun getExistingUpdateOwner(pkgInfo: PackageInfo): String? {
return try {
val packageName = pkgInfo.packageName
val sourceInfo = packageManager.getInstallSourceInfo(packageName)
- val existingUpdateOwner = sourceInfo.updateOwnerPackageName
- getApplicationLabel(existingUpdateOwner)
+ sourceInfo.updateOwnerPackageName
} catch (e: PackageManager.NameNotFoundException) {
null
}
@@ -861,7 +887,12 @@ class InstallRepository(private val context: Context) {
}
_installResult.setValue(InstallSuccess(appSnippet, shouldReturnResult, resultIntent))
} else {
- _installResult.setValue(InstallFailed(appSnippet, statusCode, legacyStatus, message))
+ if (statusCode != PackageInstaller.STATUS_FAILURE_ABORTED) {
+ _installResult.setValue(InstallFailed(appSnippet, statusCode, legacyStatus, message))
+ } else {
+ _installResult.setValue(InstallAborted(ABORT_REASON_INTERNAL_ERROR))
+ }
+
}
}
@@ -889,8 +920,8 @@ class InstallRepository(private val context: Context) {
* When the identity of the install source could not be determined, user can skip checking the
* source and directly proceed with the install.
*/
- fun forcedSkipSourceCheck(): InstallStage {
- return generateConfirmationSnippet()
+ fun forcedSkipSourceCheck(): InstallStage? {
+ return maybeDeferUserConfirmation()
}
val stagingProgress: LiveData<Int>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt
index 072fb2d34928..388e03f023a1 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt
@@ -22,6 +22,7 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.distinctUntilChanged
import com.android.packageinstaller.v2.model.InstallRepository
import com.android.packageinstaller.v2.model.InstallStage
import com.android.packageinstaller.v2.model.InstallStaging
@@ -37,6 +38,19 @@ class InstallViewModel(application: Application, val repository: InstallReposito
val currentInstallStage: MutableLiveData<InstallStage>
get() = _currentInstallStage
+ init {
+ // Since installing is an async operation, we may get the install result later in time.
+ // Result of the installation will be set in InstallRepository#installResult.
+ // As such, currentInstallStage will need to add another MutableLiveData as a data source
+ _currentInstallStage.addSource(
+ repository.installResult.distinctUntilChanged()
+ ) { installStage: InstallStage? ->
+ if (installStage != null) {
+ _currentInstallStage.value = installStage
+ }
+ }
+ }
+
fun preprocessIntent(intent: Intent, callerInfo: InstallRepository.CallerInfo) {
val stage = repository.performPreInstallChecks(intent, callerInfo)
if (stage.stageCode == InstallStage.STAGE_ABORTED) {
@@ -62,12 +76,16 @@ class InstallViewModel(application: Application, val repository: InstallReposito
private fun checkIfAllowedAndInitiateInstall() {
val stage = repository.requestUserConfirmation()
- _currentInstallStage.value = stage
+ if (stage != null) {
+ _currentInstallStage.value = stage
+ }
}
fun forcedSkipSourceCheck() {
val stage = repository.forcedSkipSourceCheck()
- _currentInstallStage.value = stage
+ if (stage != null) {
+ _currentInstallStage.value = stage
+ }
}
fun cleanupInstall() {
@@ -80,15 +98,7 @@ class InstallViewModel(application: Application, val repository: InstallReposito
}
fun initiateInstall() {
- // Since installing is an async operation, we will get the install result later in time.
- // Result of the installation will be set in InstallRepository#mInstallResult.
- // As such, mCurrentInstallStage will need to add another MutableLiveData as a data source
repository.initiateInstall()
- _currentInstallStage.addSource(repository.installResult) { installStage: InstallStage? ->
- if (installStage != null) {
- _currentInstallStage.value = installStage
- }
- }
}
val stagedSessionId: Int
diff --git a/packages/SettingsLib/HelpUtils/res/values-fi/strings.xml b/packages/SettingsLib/HelpUtils/res/values-fi/strings.xml
index de2b100a82a1..cef5080c3021 100644
--- a/packages/SettingsLib/HelpUtils/res/values-fi/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-fi/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="help_feedback_label" msgid="7106780063063027882">"Ohje ja palaute"</string>
+ <string name="help_feedback_label" msgid="7106780063063027882">"Ohjeet ja palaute"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 16dfd6d8e9c9..1594e8e75cb6 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -285,9 +285,9 @@
<string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Laat toe dat die selflaaiprogram ontsluit word"</string>
<string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Laat OEM-ontsluit toe?"</string>
<string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"WAARSKUWING: Toestelbeskermingkenmerke sal nie op hierdie toestel werk terwyl hierdie instelling aangeskakel is nie."</string>
- <string name="mock_location_app" msgid="6269380172542248304">"Kies skynliggingprogram"</string>
+ <string name="mock_location_app" msgid="6269380172542248304">"Kies skynliggingapp"</string>
<string name="mock_location_app_not_set" msgid="6972032787262831155">"Geen skynliggingprogram gestel nie"</string>
- <string name="mock_location_app_set" msgid="4706722469342913843">"Skynliggingprogram: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="mock_location_app_set" msgid="4706722469342913843">"Skynliggingapp: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="debug_networking_category" msgid="6829757985772659599">"Inligtingruiling"</string>
<string name="wifi_display_certification" msgid="1805579519992520381">"Draadlose skermsertifisering"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktiveer Wi-Fi-woordryke aanmelding"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2693ea572c2e..cfa5b1450e39 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -194,7 +194,7 @@
<string name="launch_defaults_some" msgid="3631650616557252926">"تم ضبط بعض الإعدادات التلقائية"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"لم يتم ضبط إعدادات تلقائية"</string>
<string name="tts_settings" msgid="8130616705989351312">"إعدادات تحويل النص إلى كلام"</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"الصوت عند تحويل النص إلى كلام"</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"الرد الصوتي"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"سرعة الكلام"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"سرعة قول الكلام"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"درجة الصوت"</string>
@@ -208,7 +208,7 @@
<string name="tts_install_data_title" msgid="1829942496472751703">"تثبيت البيانات الصوتية"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"تثبيت البيانات الصوتية المطلوبة لتجميع الكلام"</string>
<string name="tts_engine_security_warning" msgid="3372432853837988146">"ربما يمكن لمحرك اصطناع الحديث جمع كل النص التي سيتم نطقه، بما في ذلك البيانات الشخصية مثل كلمات المرور وأرقام بطاقة الائتمان. يتم إحضار ذلك من المحرك <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. هل تريد تفعيل استخدام محرك اصطناع الحديث هذا؟"</string>
- <string name="tts_engine_network_required" msgid="8722087649733906851">"تتطلب هذه اللغة اتصال شبكة سليمًا لتحويل النص إلى كلام."</string>
+ <string name="tts_engine_network_required" msgid="8722087649733906851">"تتطلب هذه اللغة اتصال شبكة سليمًا لاستخدام ميزة الرد الصوتي."</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"هذا مثال لتركيب الكلام"</string>
<string name="tts_status_title" msgid="8190784181389278640">"حالة اللغة التلقائية"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> متوافقة تمامًا"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 2468e065d4f0..1c6705e69efb 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Ніякі"</string>
<string name="feminine" msgid="1529155595310784757">"Жаночы"</string>
<string name="masculine" msgid="4653978041013996303">"Мужчынскі"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Абнаўленні сістэмы"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index a82d9df026a4..d6794a240054 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Среден род"</string>
<string name="feminine" msgid="1529155595310784757">"Женски род"</string>
<string name="masculine" msgid="4653978041013996303">"Мъжки род"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Системни актуализации"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index b28d896dcdf4..6fa6e12eabd2 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Střední rod"</string>
<string name="feminine" msgid="1529155595310784757">"Ženský rod"</string>
<string name="masculine" msgid="4653978041013996303">"Mužský rod"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Aktualizace systému"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 72b044714903..793560d786e3 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Neutrum"</string>
<string name="feminine" msgid="1529155595310784757">"Feminin"</string>
<string name="masculine" msgid="4653978041013996303">"Maskulin"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Systemupdates"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 70979ac4878a..0cfae920c039 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Neutro"</string>
<string name="feminine" msgid="1529155595310784757">"Femenino"</string>
<string name="masculine" msgid="4653978041013996303">"Masculino"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Actualizaciones del sistema"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index eb720493856b..497fbbb13a67 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -285,9 +285,9 @@
<string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Onartu abiarazlea desblokeatzea"</string>
<string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM desblokeoa onartu nahi duzu?"</string>
<string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"ABISUA: ezarpen hau aktibatuta dagoen bitartean, gailua babesteko eginbideek ez dute gailu honetan funtzionatuko."</string>
- <string name="mock_location_app" msgid="6269380172542248304">"Hautatu kokapen faltsuen aplikazioa"</string>
+ <string name="mock_location_app" msgid="6269380172542248304">"Hautatu asmatutako kokapenen aplikazioa"</string>
<string name="mock_location_app_not_set" msgid="6972032787262831155">"Ez da ezarri kokapen faltsuen aplikaziorik"</string>
- <string name="mock_location_app_set" msgid="4706722469342913843">"Kokapen faltsuen aplikazioa: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="mock_location_app_set" msgid="4706722469342913843">"Asmatutako kokapenen aplikazioa: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="debug_networking_category" msgid="6829757985772659599">"Sareak"</string>
<string name="wifi_display_certification" msgid="1805579519992520381">"Hari gabe bistaratzeko ziurtagiria"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Gaitu wifi-sareetan saioa hasteko modu xehatua"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 72b31e2d5411..5e7f998a7e41 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -159,7 +159,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"لغو"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"وقتی وصل باشید، مرتبط‌سازی اجازه دسترسی به مخاطبین و سابقه تماستان را فراهم می‌کند."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"با <xliff:g id="DEVICE_NAME">%1$s</xliff:g> مرتبط‌سازی نشد."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"به‌دلیل پین یا گذرکلید نادرست، مرتبط‌سازی با <xliff:g id="DEVICE_NAME">%1$s</xliff:g> انجام نشد."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"به‌دلیل پین یا گذرکلید نادرست، جفت‌سازی با <xliff:g id="DEVICE_NAME">%1$s</xliff:g> انجام نشد."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"ارتباط با <xliff:g id="DEVICE_NAME">%1$s</xliff:g> امکان‌پذیر نیست."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> مرتبط‌سازی را رد کرد."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"رایانه"</string>
@@ -236,7 +236,7 @@
<string name="category_personal" msgid="6236798763159385225">"شخصی"</string>
<string name="category_work" msgid="4014193632325996115">"کاری"</string>
<string name="category_private" msgid="4244892185452788977">"خصوصی"</string>
- <string name="category_clone" msgid="1554511758987195974">"مشابه‌سازی"</string>
+ <string name="category_clone" msgid="1554511758987195974">"همسانه‌سازی"</string>
<string name="development_settings_title" msgid="140296922921597393">"گزینه‌های برنامه‌نویسان"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"فعال کردن گزینه‌های برنامه‌نویس"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"تنظیم گزینه‌های مربوط به طراحی برنامه"</string>
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"خنثی"</string>
<string name="feminine" msgid="1529155595310784757">"مؤنث"</string>
<string name="masculine" msgid="4653978041013996303">"مذکر"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"به‌روزرسانی‌های سیستم"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index dc11d5f47cbb..bdf4301c5c7a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -159,7 +159,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Peru"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Laiteparin muodostaminen mahdollistaa yhteystietojen ja soittohistorian käyttämisen yhteyden aikana."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Laiteparin muodostaminen laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g> epäonnistui."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Laiteparia (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) ei voitu muodostaa, koska PIN tai avain oli väärä."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Laiteparia (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) ei voitu muodostaa, koska PIN tai avainkoodi oli väärä."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Ei yhteyttä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Laite <xliff:g id="DEVICE_NAME">%1$s</xliff:g> torjui laitepariyhteyden."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Tietokone"</string>
@@ -593,7 +593,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Sisäiset kaiuttimet"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
- <string name="help_label" msgid="3528360748637781274">"Ohje ja palaute"</string>
+ <string name="help_label" msgid="3528360748637781274">"Ohjeet ja palaute"</string>
<string name="storage_category" msgid="2287342585424631813">"Tallennustila"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Jaettu data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Katso ja muokkaa jaettua dataa"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 6ba4e8373a4a..090c3b9613e1 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -285,7 +285,7 @@
<string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Autoriser le déverrouillage du fichier d\'amorce"</string>
<string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Permettre le déverrouillage par le fabricant?"</string>
<string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"AVERTISSEMENT : Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sur cet appareil lorsque ce paramètre est activé."</string>
- <string name="mock_location_app" msgid="6269380172542248304">"Sélectionner l\'application de position fictive"</string>
+ <string name="mock_location_app" msgid="6269380172542248304">"Sélectionner l\'appli de position fictive"</string>
<string name="mock_location_app_not_set" msgid="6972032787262831155">"Aucune application de position fictive définie"</string>
<string name="mock_location_app_set" msgid="4706722469342913843">"Application de position fictive : <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="debug_networking_category" msgid="6829757985772659599">"Réseautage"</string>
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Neutre"</string>
<string name="feminine" msgid="1529155595310784757">"Féminin"</string>
<string name="masculine" msgid="4653978041013996303">"Masculin"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Mises à jour du système"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index b4639247b4a6..21d0bcdef6f9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -159,7 +159,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Cancelar"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"A vinculación garante acceso aos teus contactos e ao historial de chamadas ao estar conectado"</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Non se puido vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Non se puido vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, clave de acceso ou PIN incorrectos."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Non se puido vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>; clave de acceso ou PIN incorrectos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Non se pode comunicar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Vinculación rexeitada por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Ordenador"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index f026298eee0c..e434d1efaabf 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -370,7 +370,7 @@
<string name="debug_hw_drawing_category" msgid="5830815169336975162">"हार्डवेयर ऐक्सेलरेटेड रेंडरिंग"</string>
<string name="media_category" msgid="8122076702526144053">"मीडिया"</string>
<string name="debug_monitoring_category" msgid="1597387133765424994">"निगरानी"</string>
- <string name="strict_mode" msgid="889864762140862437">"स्ट्रिक्ट मोड चालू किया गया"</string>
+ <string name="strict_mode" msgid="889864762140862437">"स्ट्रिक्ट मोड चालू रखें"</string>
<string name="strict_mode_summary" msgid="1838248687233554654">"थ्रेड पर लंबा प्रोसेस होने पर स्‍क्रीन फ़्लैश करें"</string>
<string name="pointer_location" msgid="7516929526199520173">"पॉइंटर की जगह"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"मौजूदा टच डेटा दिखाने वाला स्‍क्रीन ओवरले"</string>
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"नपुंसक लिंग"</string>
<string name="feminine" msgid="1529155595310784757">"महिला"</string>
<string name="masculine" msgid="4653978041013996303">"पुरुष"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"सिस्टम अपडेट"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index e7916a33ff3e..0aba7cd1d9aa 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Srednji rod"</string>
<string name="feminine" msgid="1529155595310784757">"Ženski rod"</string>
<string name="masculine" msgid="4653978041013996303">"Muški rod"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Ažuriranja sustava"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 81d59f533b9f..c232396875fd 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"ניטרלי"</string>
<string name="feminine" msgid="1529155595310784757">"נקבה"</string>
<string name="masculine" msgid="4653978041013996303">"זכר"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"עדכוני מערכת"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 1e0f9b0380a8..4d2f8fc8a809 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"中性"</string>
<string name="feminine" msgid="1529155595310784757">"女性"</string>
<string name="masculine" msgid="4653978041013996303">"男性"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"システム アップデート"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 44fd9c807780..4e034b456f50 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -371,7 +371,7 @@
<string name="media_category" msgid="8122076702526144053">"Mультимeдиа"</string>
<string name="debug_monitoring_category" msgid="1597387133765424994">"Бақылау"</string>
<string name="strict_mode" msgid="889864762140862437">"Қатаң режим қосылған"</string>
- <string name="strict_mode_summary" msgid="1838248687233554654">"Қолданбалар негізгі жолда ұзақ әрекеттерді орындағанда экранды жыпылықтату"</string>
+ <string name="strict_mode_summary" msgid="1838248687233554654">"Қолданбалар ұзақ операцияларды орындағанда экранды жыпылықтату"</string>
<string name="pointer_location" msgid="7516929526199520173">"Меңзер орны"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"Экран бетіне түртілген элемент дерегі көрсетіледі"</string>
<string name="show_touches" msgid="8437666942161289025">"Түрту қимылын көрсету"</string>
@@ -390,7 +390,7 @@
<string name="simulate_color_space" msgid="1206503300335835151">"Түстер кеңістігінің симуляциясы"</string>
<string name="enable_opengl_traces_title" msgid="4638773318659125196">"OpenGL трейстерін қосу"</string>
<string name="usb_audio_disable_routing" msgid="3367656923544254975">"USB-мен аудио жіберуді өшіру"</string>
- <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Сыртқы USB аудио құрылғыларына автоматты жіберуді өшіру"</string>
+ <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Сыртқы USB аудио құрылғыларына автоматты түрде жіберуді өшіру"</string>
<string name="debug_layout" msgid="1659216803043339741">"Жиектерді көрсету"</string>
<string name="debug_layout_summary" msgid="8825829038287321978">"Қию шегін, шеттерді, т.б. көрсету"</string>
<string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"Оңнан солға орналастыру"</string>
@@ -595,7 +595,7 @@
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
<string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
<string name="storage_category" msgid="2287342585424631813">"Жад"</string>
- <string name="shared_data_title" msgid="1017034836800864953">"Бөліскен дерек"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"Ортақ дерек"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ортақ деректерді көру және өзгерту"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Бұл пайдаланушымен бөліскен дерек жоқ."</string>
<string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ортақ деректер алу кезінде қате шықты. Қайталап көріңіз."</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index f950b0c3b8f9..60f88ead0795 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"អភេទ"</string>
<string name="feminine" msgid="1529155595310784757">"ស្រី"</string>
<string name="masculine" msgid="4653978041013996303">"ប្រុស"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"បច្ចុប្បន្នភាព​ប្រព័ន្ធ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index a883cebb5bae..d93af73c6a56 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"중성"</string>
<string name="feminine" msgid="1529155595310784757">"여성"</string>
<string name="masculine" msgid="4653978041013996303">"남성"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"시스템 업데이트"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 247dac1656d2..a6040ef0b434 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -371,7 +371,7 @@
<string name="media_category" msgid="8122076702526144053">"ມີເດຍ"</string>
<string name="debug_monitoring_category" msgid="1597387133765424994">"ກຳລັງກວດສອບ"</string>
<string name="strict_mode" msgid="889864762140862437">"ເປີດໃຊ້ໂໝດເຄັ່ງຄັດ"</string>
- <string name="strict_mode_summary" msgid="1838248687233554654">"ກະພິບໜ້າຈໍເມື່ອມີແອັບ ເຮັດວຽກດົນເກີນໄປໃນເທຣດຫຼັກ"</string>
+ <string name="strict_mode_summary" msgid="1838248687233554654">"ກະພິບໜ້າຈໍເມື່ອມີແອັບເຮັດວຽກດົນເກີນໄປໃນເທຣດຫຼັກ"</string>
<string name="pointer_location" msgid="7516929526199520173">"ຕຳແໜ່ງໂຕຊີ້"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"ການວາງຊ້ອນໜ້າຈໍກຳລັງສະແດງຂໍ້ມູນການສຳຜັດໃນປັດຈຸບັນ"</string>
<string name="show_touches" msgid="8437666942161289025">"ສະແດງການແຕະ"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 3dd40ee6a115..c07fae3894c3 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -96,8 +96,8 @@
<string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Savienojums izveidots (nav tālrunis vai multivide) (<xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>), akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Aktīvs. Akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
<string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"Aktīvs. Akumulatora uzlādes līmenis kreisajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, labajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
- <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Aktīvs. Kreisā: akumulatora uzlādes līmenis ir <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
- <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Aktīvs. Labā: akumulatora uzlādes līmenis ir <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
+ <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Aktīvs. Kreisā puse: akumulatora uzlādes līmenis ir <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
+ <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Aktīvs. Labā puse: akumulatora uzlādes līmenis ir <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Akumulatora uzlādes līmenis kreisajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, labajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index f679de56e3e2..4cd076b77fb9 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -371,7 +371,7 @@
<string name="media_category" msgid="8122076702526144053">"Аудиовизуелни содржини"</string>
<string name="debug_monitoring_category" msgid="1597387133765424994">"Следење"</string>
<string name="strict_mode" msgid="889864762140862437">"Овозможен е строг режим"</string>
- <string name="strict_mode_summary" msgid="1838248687233554654">"Осветли екран при долги операции на главна нишка"</string>
+ <string name="strict_mode_summary" msgid="1838248687233554654">"Трепкај со екранот при долги операции на главна нишка"</string>
<string name="pointer_location" msgid="7516929526199520173">"Локација на покажувач"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"Прекривката на екран ги покажува тековните податоци на допир"</string>
<string name="show_touches" msgid="8437666942161289025">"Прикажувај допири"</string>
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Среден род"</string>
<string name="feminine" msgid="1529155595310784757">"Женски род"</string>
<string name="masculine" msgid="4653978041013996303">"Машки род"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Системски ажурирања"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 6b7fae7d39ce..b3317e426598 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -159,7 +159,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"မလုပ်တော့"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"ချိတ်တွဲမှုက ချိတ်ဆက်ထားလျှင် သင်၏ အဆက်အသွယ်များ နှင့် ခေါ်ဆိုမှု မှတ်တမ်းကို ရယူခွင့် ပြုသည်။"</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> နှင့် တွဲချိတ်မရပါ"</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"ပင်နံပါတ် (သို့) ဖြတ်သန်းခွင့်ကီး မမှန်ကန်သောကြောင့် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> နှင့် တွဲချိတ်၍မရပါ။"</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"ပင်နံပါတ် (သို့) လျှို့ဝှက်ကီး မမှန်ကန်သောကြောင့် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> နှင့် တွဲချိတ်၍မရပါ။"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့်ဆက်သွယ်မရပါ"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့်တွဲချိတ်ရန် ပယ်ချခံရသည်"</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"ကွန်ပျူတာ"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 879752d8e722..40d604e39954 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -159,7 +159,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"रद्द गर्नुहोस्"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"जब जडान हुन्छ जोडी अनुदानले तपाईँको सम्पर्कहरू पहुँच गर्छ र इतिहास सम्झाउँछ।"</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>सँग जोडा मिलाउन सकेन"</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"गलत PIN वा पासकीका कारणले <xliff:g id="DEVICE_NAME">%1$s</xliff:g> सँग कनेक्ट गर्न सकिएन।"</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"गलत PIN वा पासकीका कारणले <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा कनेक्ट गर्न सकिएन।"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सँग कुराकानी हुन सक्दैन।"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारा जोडा बाँध्ने कार्य अस्वीकृत"</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"कम्प्युटर"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 9090efdbcf89..422d0f2c6256 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -575,7 +575,7 @@
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
- <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telefone"</string>
+ <string name="media_transfer_this_phone" msgid="7194341457812151531">"Neste telefone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível abrir os downloads aqui"</string>
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Neutro"</string>
<string name="feminine" msgid="1529155595310784757">"Feminino"</string>
<string name="masculine" msgid="4653978041013996303">"Masculino"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Atualizações do sistema"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 6d2d7e6be99d..0bcca1566a8e 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Neutro"</string>
<string name="feminine" msgid="1529155595310784757">"Feminino"</string>
<string name="masculine" msgid="4653978041013996303">"Masculino"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Atualizações do sistema"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 9090efdbcf89..422d0f2c6256 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -575,7 +575,7 @@
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
- <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telefone"</string>
+ <string name="media_transfer_this_phone" msgid="7194341457812151531">"Neste telefone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível abrir os downloads aqui"</string>
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Neutro"</string>
<string name="feminine" msgid="1529155595310784757">"Feminino"</string>
<string name="masculine" msgid="4653978041013996303">"Masculino"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Atualizações do sistema"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index c02e65ba1653..54c9b0a71980 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -159,7 +159,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Отмена"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Установление соединения обеспечивает доступ к вашим контактам и журналу звонков при подключении."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Не удалось подключиться к устройству \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"\"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" не подключается: неверный PIN-код или пароль."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Устройство \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" не подключено: неверный PIN-код или пароль."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Не удается установить соединение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> не разрешает подключение."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Компьютер"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 3db9f409a813..ab423b5d7f93 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"නපුංසක"</string>
<string name="feminine" msgid="1529155595310784757">"ස්ත්‍රී"</string>
<string name="masculine" msgid="4653978041013996303">"පුරුෂ"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"පද්ධති යාවත්කාලීන"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 114adfd4bfca..cc3243209c43 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Neutrum"</string>
<string name="feminine" msgid="1529155595310784757">"Femin­informer"</string>
<string name="masculine" msgid="4653978041013996303">"Maskulinformer"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Systemuppdateringar"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 56b28d8de326..0eac15c4a9d6 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Isiyobainika"</string>
<string name="feminine" msgid="1529155595310784757">"Jinsia ya kike"</string>
<string name="masculine" msgid="4653978041013996303">"Jinsia ya kiume"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Masasisho ya Mfumo"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 47c5993f0c68..7c87eb7ff885 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"அஃறிணை"</string>
<string name="feminine" msgid="1529155595310784757">"பெண்"</string>
<string name="masculine" msgid="4653978041013996303">"ஆண்"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"சிஸ்டம் புதுப்பிப்புகள்"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 766f9b2770ee..689ea6f11c95 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -159,7 +159,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"రద్దు చేయండి"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"పెయిర్ చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ కాంటాక్ట్‌లకు అలాగే కాల్ హిస్టరీకి యాక్సెస్‌ను మంజూరు చేస్తుంది."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో జత చేయడం సాధ్యపడలేదు."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"PIN లేదా పాస్‌కీ చెల్లని కారణంగా <xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో పెయిర్ చేయడం సాధ్యపడలేదు."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"PIN గానీ, పాస్‌కీ గానీ చెల్లని కారణంగా <xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో పెయిర్ చేయడం సాధ్యపడలేదు."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో కమ్యూనికేట్ చేయడం సాధ్యపడదు."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> జత చేయడాన్ని తిరస్కరించింది."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"కంప్యూటర్"</string>
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"తటస్థం"</string>
<string name="feminine" msgid="1529155595310784757">"స్త్రీ"</string>
<string name="masculine" msgid="4653978041013996303">"పురుషుడు"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"సిస్టమ్ అప్‌డేట్‌లు"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 79d8fe13b1f3..1899914428c7 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"ไม่มีเพศ"</string>
<string name="feminine" msgid="1529155595310784757">"เพศหญิง"</string>
<string name="masculine" msgid="4653978041013996303">"เพศชาย"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"การอัปเดตระบบ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 6719bb0bb74d..144c20b7b1e4 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Cinsiyetsiz"</string>
<string name="feminine" msgid="1529155595310784757">"Kadın"</string>
<string name="masculine" msgid="4653978041013996303">"Erkek"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Sistem Güncellemeleri"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 10b47d9d2bfe..ecfa2c90049c 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -721,6 +721,5 @@
<string name="neuter" msgid="2075249330106127310">"Середній рід"</string>
<string name="feminine" msgid="1529155595310784757">"Жіночий рід"</string>
<string name="masculine" msgid="4653978041013996303">"Чоловічий рід"</string>
- <!-- no translation found for system_update_settings_list_item_title (6618098383615432484) -->
- <skip />
+ <string name="system_update_settings_list_item_title" msgid="6618098383615432484">"Оновлення системи"</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a7b7da598d12..30bec7724dd5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -649,6 +649,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
for (CachedBluetoothDevice cbd : mMemberDevices) {
cbd.setName(name);
}
+ if (mSubDevice != null) {
+ mSubDevice.setName(name);
+ }
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index 9bf42f9396e3..ed964a9d0f40 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -100,6 +100,7 @@ public class HearingAidDeviceManager {
// device.
if (hearingAidDevice != null) {
hearingAidDevice.setSubDevice(newDevice);
+ newDevice.setName(hearingAidDevice.getName());
return true;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
index 8e3df8bcc2dd..2de2174a404b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
@@ -48,17 +48,15 @@ public final class HearingAidStatsLogUtils {
private static final String BT_HEARING_AIDS_PAIRED_HISTORY = "bt_hearing_aids_paired_history";
private static final String BT_HEARING_AIDS_CONNECTED_HISTORY =
"bt_hearing_aids_connected_history";
- private static final String BT_HEARING_DEVICES_PAIRED_HISTORY =
+ private static final String BT_HEARABLE_DEVICES_PAIRED_HISTORY =
"bt_hearing_devices_paired_history";
- private static final String BT_HEARING_DEVICES_CONNECTED_HISTORY =
+ private static final String BT_HEARABLE_DEVICES_CONNECTED_HISTORY =
"bt_hearing_devices_connected_history";
- private static final String BT_HEARING_USER_CATEGORY = "bt_hearing_user_category";
-
private static final String HISTORY_RECORD_DELIMITER = ",";
static final String CATEGORY_HEARING_AIDS = "A11yHearingAidsUser";
static final String CATEGORY_NEW_HEARING_AIDS = "A11yNewHearingAidsUser";
- static final String CATEGORY_HEARING_DEVICES = "A11yHearingDevicesUser";
- static final String CATEGORY_NEW_HEARING_DEVICES = "A11yNewHearingDevicesUser";
+ static final String CATEGORY_HEARABLE_DEVICES = "A11yHearingDevicesUser";
+ static final String CATEGORY_NEW_HEARABLE_DEVICES = "A11yNewHearingDevicesUser";
static final int PAIRED_HISTORY_EXPIRED_DAY = 30;
static final int CONNECTED_HISTORY_EXPIRED_DAY = 7;
@@ -73,14 +71,14 @@ public final class HearingAidStatsLogUtils {
HistoryType.TYPE_UNKNOWN,
HistoryType.TYPE_HEARING_AIDS_PAIRED,
HistoryType.TYPE_HEARING_AIDS_CONNECTED,
- HistoryType.TYPE_HEARING_DEVICES_PAIRED,
- HistoryType.TYPE_HEARING_DEVICES_CONNECTED})
+ HistoryType.TYPE_HEARABLE_DEVICES_PAIRED,
+ HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED})
public @interface HistoryType {
int TYPE_UNKNOWN = -1;
int TYPE_HEARING_AIDS_PAIRED = 0;
int TYPE_HEARING_AIDS_CONNECTED = 1;
- int TYPE_HEARING_DEVICES_PAIRED = 2;
- int TYPE_HEARING_DEVICES_CONNECTED = 3;
+ int TYPE_HEARABLE_DEVICES_PAIRED = 2;
+ int TYPE_HEARABLE_DEVICES_CONNECTED = 3;
}
private static final HashMap<String, Integer> sDeviceAddressToBondEntryMap = new HashMap<>();
@@ -127,8 +125,8 @@ public final class HearingAidStatsLogUtils {
}
/**
- * Updates corresponding history if we found the device is a hearing device after profile state
- * changed.
+ * Updates corresponding history if we found the device is a hearing related device after
+ * profile state changed.
*
* @param context the request context
* @param cachedDevice the remote device
@@ -148,7 +146,7 @@ public final class HearingAidStatsLogUtils {
} else if (cachedDevice.getProfiles().stream().anyMatch(
p -> (p instanceof A2dpSinkProfile || p instanceof HeadsetProfile))) {
HearingAidStatsLogUtils.addCurrentTimeToHistory(context,
- HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED);
+ HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED);
}
removeFromJustBonded(cachedDevice.getAddress());
}
@@ -161,7 +159,7 @@ public final class HearingAidStatsLogUtils {
HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_CONNECTED);
} else if (profile instanceof A2dpSinkProfile || profile instanceof HeadsetProfile) {
HearingAidStatsLogUtils.addCurrentTimeToHistory(context,
- HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED);
+ HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED);
}
}
}
@@ -169,18 +167,13 @@ public final class HearingAidStatsLogUtils {
/**
* Returns the user category if the user is already categorized. Otherwise, checks the
* history and sees if the user is categorized as one of {@link #CATEGORY_HEARING_AIDS},
- * {@link #CATEGORY_NEW_HEARING_AIDS}, {@link #CATEGORY_HEARING_DEVICES}, and
- * {@link #CATEGORY_NEW_HEARING_DEVICES}.
+ * {@link #CATEGORY_NEW_HEARING_AIDS}, {@link #CATEGORY_HEARABLE_DEVICES}, and
+ * {@link #CATEGORY_NEW_HEARABLE_DEVICES}.
*
* @param context the request context
* @return the category which user belongs to
*/
public static synchronized String getUserCategory(Context context) {
- String userCategory = getSharedPreferences(context).getString(BT_HEARING_USER_CATEGORY, "");
- if (!userCategory.isEmpty()) {
- return userCategory;
- }
-
LinkedList<Long> hearingAidsConnectedHistory = getHistory(context,
HistoryType.TYPE_HEARING_AIDS_CONNECTED);
if (hearingAidsConnectedHistory != null
@@ -192,29 +185,29 @@ public final class HearingAidStatsLogUtils {
// will be categorized as CATEGORY_HEARING_AIDS.
if (hearingAidsPairedHistory != null
&& hearingAidsPairedHistory.size() >= VALID_PAIRED_EVENT_COUNT) {
- userCategory = CATEGORY_NEW_HEARING_AIDS;
+ return CATEGORY_NEW_HEARING_AIDS;
} else {
- userCategory = CATEGORY_HEARING_AIDS;
+ return CATEGORY_HEARING_AIDS;
}
}
- LinkedList<Long> hearingDevicesConnectedHistory = getHistory(context,
- HistoryType.TYPE_HEARING_DEVICES_CONNECTED);
- if (hearingDevicesConnectedHistory != null
- && hearingDevicesConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) {
- LinkedList<Long> hearingDevicesPairedHistory = getHistory(context,
- HistoryType.TYPE_HEARING_DEVICES_PAIRED);
+ LinkedList<Long> hearableDevicesConnectedHistory = getHistory(context,
+ HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED);
+ if (hearableDevicesConnectedHistory != null
+ && hearableDevicesConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) {
+ LinkedList<Long> hearableDevicesPairedHistory = getHistory(context,
+ HistoryType.TYPE_HEARABLE_DEVICES_PAIRED);
// Since paired history will be cleared after 30 days. If there's any record within 30
- // days, the user will be categorized as CATEGORY_NEW_HEARING_DEVICES. Otherwise, the
- // user will be categorized as CATEGORY_HEARING_DEVICES.
- if (hearingDevicesPairedHistory != null
- && hearingDevicesPairedHistory.size() >= VALID_PAIRED_EVENT_COUNT) {
- userCategory = CATEGORY_NEW_HEARING_DEVICES;
+ // days, the user will be categorized as CATEGORY_NEW_HEARABLE_DEVICES. Otherwise, the
+ // user will be categorized as CATEGORY_HEARABLE_DEVICES.
+ if (hearableDevicesPairedHistory != null
+ && hearableDevicesPairedHistory.size() >= VALID_PAIRED_EVENT_COUNT) {
+ return CATEGORY_NEW_HEARABLE_DEVICES;
} else {
- userCategory = CATEGORY_HEARING_DEVICES;
+ return CATEGORY_HEARABLE_DEVICES;
}
}
- return userCategory;
+ return "";
}
/**
@@ -245,7 +238,7 @@ public final class HearingAidStatsLogUtils {
}
/**
- * Adds current timestamp into BT hearing devices related history.
+ * Adds current timestamp into BT hearing related devices history.
* @param context the request context
* @param type the type of history to store the data. See {@link HistoryType}.
*/
@@ -279,13 +272,13 @@ public final class HearingAidStatsLogUtils {
static synchronized LinkedList<Long> getHistory(Context context, @HistoryType int type) {
String spName = HISTORY_TYPE_TO_SP_NAME_MAPPING.get(type);
if (BT_HEARING_AIDS_PAIRED_HISTORY.equals(spName)
- || BT_HEARING_DEVICES_PAIRED_HISTORY.equals(spName)) {
+ || BT_HEARABLE_DEVICES_PAIRED_HISTORY.equals(spName)) {
LinkedList<Long> history = convertToHistoryList(
getSharedPreferences(context).getString(spName, ""));
removeRecordsBeforeDay(history, PAIRED_HISTORY_EXPIRED_DAY);
return history;
} else if (BT_HEARING_AIDS_CONNECTED_HISTORY.equals(spName)
- || BT_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName)) {
+ || BT_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName)) {
LinkedList<Long> history = convertToHistoryList(
getSharedPreferences(context).getString(spName, ""));
removeRecordsBeforeDay(history, CONNECTED_HISTORY_EXPIRED_DAY);
@@ -352,9 +345,9 @@ public final class HearingAidStatsLogUtils {
HISTORY_TYPE_TO_SP_NAME_MAPPING.put(
HistoryType.TYPE_HEARING_AIDS_CONNECTED, BT_HEARING_AIDS_CONNECTED_HISTORY);
HISTORY_TYPE_TO_SP_NAME_MAPPING.put(
- HistoryType.TYPE_HEARING_DEVICES_PAIRED, BT_HEARING_DEVICES_PAIRED_HISTORY);
+ HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, BT_HEARABLE_DEVICES_PAIRED_HISTORY);
HISTORY_TYPE_TO_SP_NAME_MAPPING.put(
- HistoryType.TYPE_HEARING_DEVICES_CONNECTED, BT_HEARING_DEVICES_CONNECTED_HISTORY);
+ HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, BT_HEARABLE_DEVICES_CONNECTED_HISTORY);
}
private HearingAidStatsLogUtils() {}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index b356f542f480..b4bd4826ea08 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -1703,6 +1703,30 @@ public class CachedBluetoothDeviceTest {
}
@Test
+ public void setName_memberDeviceNameIsSet() {
+ when(mDevice.getAlias()).thenReturn(DEVICE_NAME);
+ when(mSubDevice.getAlias()).thenReturn(DEVICE_NAME);
+
+ mCachedDevice.addMemberDevice(mSubCachedDevice);
+ mCachedDevice.setName(DEVICE_ALIAS);
+
+ verify(mDevice).setAlias(DEVICE_ALIAS);
+ verify(mSubDevice).setAlias(DEVICE_ALIAS);
+ }
+
+ @Test
+ public void setName_subDeviceNameIsSet() {
+ when(mDevice.getAlias()).thenReturn(DEVICE_NAME);
+ when(mSubDevice.getAlias()).thenReturn(DEVICE_NAME);
+
+ mCachedDevice.setSubDevice(mSubCachedDevice);
+ mCachedDevice.setName(DEVICE_ALIAS);
+
+ verify(mDevice).setAlias(DEVICE_ALIAS);
+ verify(mSubDevice).setAlias(DEVICE_ALIAS);
+ }
+
+ @Test
public void getProfileConnectionState_nullProfile_returnDisconnected() {
assertThat(mCachedDevice.getProfileConnectionState(null)).isEqualTo(
BluetoothProfile.STATE_DISCONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index 1f0da90ed028..4188d2ec7aaa 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -299,6 +299,7 @@ public class HearingAidDeviceManagerTest {
mHearingAidDeviceManager.setSubDeviceIfNeeded(mCachedDevice2);
assertThat(mCachedDevice1.getSubDevice()).isEqualTo(mCachedDevice2);
+ verify(mDevice2).setAlias(DEVICE_ALIAS_1);
}
/**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
index bd5a022e44e5..cd1672104c5a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
@@ -145,20 +145,29 @@ public class HearingAidStatsLogUtilsTest {
}
@Test
- public void getUserCategory_hearingDevicesUser() {
- prepareHearingDevicesUserHistory();
+ public void getUserCategory_hearableDevicesUser() {
+ prepareHearableDevicesUserHistory();
assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo(
- HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES);
+ HearingAidStatsLogUtils.CATEGORY_HEARABLE_DEVICES);
}
@Test
- public void getUserCategory_newHearingDevicesUser() {
- prepareHearingDevicesUserHistory();
+ public void getUserCategory_newHearableDevicesUser() {
+ prepareHearableDevicesUserHistory();
prepareNewUserHistory();
assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo(
- HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_DEVICES);
+ HearingAidStatsLogUtils.CATEGORY_NEW_HEARABLE_DEVICES);
+ }
+
+ @Test
+ public void getUserCategory_bothHearingAidsAndHearableDevicesUser_returnHearingAidsUser() {
+ prepareHearingAidsUserHistory();
+ prepareHearableDevicesUserHistory();
+
+ assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo(
+ HearingAidStatsLogUtils.CATEGORY_HEARING_AIDS);
}
private long convertToStartOfDayTime(long timestamp) {
@@ -176,12 +185,12 @@ public class HearingAidStatsLogUtilsTest {
}
}
- private void prepareHearingDevicesUserHistory() {
+ private void prepareHearableDevicesUserHistory() {
final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis());
for (int i = CONNECTED_HISTORY_EXPIRED_DAY - 1; i >= 0; i--) {
final long data = todayStartOfDay - TimeUnit.DAYS.toMillis(i);
HearingAidStatsLogUtils.addToHistory(mContext,
- HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, data);
+ HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, data);
}
}
@@ -191,6 +200,6 @@ public class HearingAidStatsLogUtilsTest {
HearingAidStatsLogUtils.addToHistory(mContext,
HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_PAIRED, data);
HearingAidStatsLogUtils.addToHistory(mContext,
- HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED, data);
+ HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, data);
}
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 65c570840368..fce7a00f9744 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -382,6 +382,7 @@ android_library {
"androidx.compose.material_material-icons-extended",
"androidx.activity_activity-compose",
"androidx.compose.animation_animation-graphics",
+ "device_policy_aconfig_flags_lib",
],
libs: [
"keepanno-annotations",
@@ -622,6 +623,7 @@ android_app {
"//frameworks/libs/systemui:compilelib",
"SystemUI-tests-base",
"androidx.compose.runtime_runtime",
+ "SystemUI-core",
],
libs: [
"keepanno-annotations",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 59e2b9175711..b9e70ef14007 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1110,7 +1110,7 @@
android:resource="@xml/home_controls_dream_metadata" />
</service>
- <activity android:name="com.android.systemui.keyboard.shortcut.ShortcutHelperActivity"
+ <activity android:name="com.android.systemui.keyboard.shortcut.ui.view.ShortcutHelperActivity"
android:exported="false"
android:theme="@style/ShortcutHelperTheme"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 796e3914f3c1..d2e5a13adfce 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -4,13 +4,13 @@ set noparent
dsandler@android.com
-aaronjli@google.com
achalke@google.com
acul@google.com
adamcohen@google.com
aioana@google.com
alexflo@google.com
andonian@google.com
+amiko@google.com
aroederer@google.com
arteiro@google.com
asc@google.com
@@ -39,7 +39,6 @@ hwwang@google.com
hyunyoungs@google.com
ikateryna@google.com
iyz@google.com
-jamesoleary@google.com
jbolinger@google.com
jdemeulenaere@google.com
jeffdq@google.com
@@ -82,6 +81,7 @@ pixel@google.com
pomini@google.com
princedonkor@google.com
rahulbanerjee@google.com
+rgl@google.com
roosa@google.com
saff@google.com
santie@google.com
@@ -110,6 +110,3 @@ yeinj@google.com
yuandizhou@google.com
yurilin@google.com
zakcohen@google.com
-
-#Android TV
-rgl@google.com
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 0c89a5dcbcf4..deab81856afa 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -59,13 +59,16 @@
]
}
],
-
+
"auto-end-to-end-postsubmit": [
{
"name": "AndroidAutomotiveHomeTests",
"options" : [
{
"include-filter": "android.platform.tests.HomeTest"
+ },
+ {
+ "exclude-filter": "android.platform.tests.HomeTest#testAssistantWidget"
}
]
},
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml
index 15eb928c1ced..be1916fe4f4e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml
@@ -2,7 +2,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="accessibility_menu_service_name" msgid="730136711554740131">"Nabídka usnadnění přístupu"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"Nabídka usnadnění přístupu zobrazuje na obrazovce velkou nabídku k ovládání zařízení. Můžete zamknout zařízení, upravit hlasitost a jas, pořídit snímek obrazovky apod."</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Nabídka usnadnění přístupu zobrazuje na obrazovce velkou nabídku k ovládání zařízení – například k jeho zamknutí, úpravě hlasitosti a jasu, pořízení snímku obrazovky apod."</string>
<string name="assistant_label" msgid="6796392082252272356">"Asistent"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Nastavení usnadnění přístupu"</string>
@@ -20,7 +20,7 @@
<string name="brightness_down_label" msgid="7115662941913272072">"Snížit jas"</string>
<string name="previous_button_content_description" msgid="840869171117765966">"Zpět na předchozí obrazovku"</string>
<string name="next_button_content_description" msgid="6810058269847364406">"Přejít na další obrazovku"</string>
- <string name="accessibility_menu_description" msgid="4458354794093858297">"Nabídka usnadnění přístupu zobrazuje na obrazovce velkou nabídku k ovládání zařízení. Můžete zamknout zařízení, upravit hlasitost a jas, pořídit snímek obrazovky apod."</string>
+ <string name="accessibility_menu_description" msgid="4458354794093858297">"Nabídka usnadnění přístupu zobrazuje na obrazovce velkou nabídku k ovládání zařízení – například k jeho zamknutí, úpravě hlasitosti a jasu, pořízení snímku obrazovky apod."</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"Ovládání zařízení pomocí velké nabídky"</string>
<string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Nastavení nabídky usnadnění přístupu"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Velká tlačítka"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml
index b314c8eaea1d..1e21c775ffd9 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml
@@ -20,7 +20,7 @@
<string name="brightness_down_label" msgid="7115662941913272072">"Txikitu distira"</string>
<string name="previous_button_content_description" msgid="840869171117765966">"Joan aurreko pantailara"</string>
<string name="next_button_content_description" msgid="6810058269847364406">"Joan hurrengo pantailara"</string>
- <string name="accessibility_menu_description" msgid="4458354794093858297">"Erabilerraztasun-menuari esker, tamaina handiko menu bat izango duzu pantailan; menu horren bidez, gailua kontrolatzeko aukera izango duzu. Besteak beste, hauek egin ahalko dituzu: gailua blokeatu; bolumena eta distira kontrolatu, eta pantaila-argazkiak egin."</string>
+ <string name="accessibility_menu_description" msgid="4458354794093858297">"Erabilerraztasun-menuari esker, tamaina handiko menu bat izango duzu pantailan; menu horren bidez, gailua kontrolatzeko aukera izango duzu. Besteak beste, hauek egin ahalko dituzu: gailua blokeatu, bolumena eta distira kontrolatu, eta pantaila-argazkiak egin."</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"Kontrolatu gailua menu handiaren bidez"</string>
<string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Erabilerraztasun-menuaren ezarpenak"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Botoi handiak"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml
index eff6cb45309b..5c3c99c59abc 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml
@@ -2,7 +2,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="accessibility_menu_service_name" msgid="730136711554740131">"Izbornik pristupačnosti"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"Izbornik pristupačnosti veliki je zaslonski izbornik koji vam omogućuje upravljanje uređajem. Putem ovog izbornika možete zaključati uređaj, upravljati glasnoćom i svjetlinom, izrađivati snimke zaslona i drugo."</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Izbornik pristupačnosti veliki je zaslonski izbornik koji vam omogućuje upravljanje uređajem. Putem njega možete zaključati uređaj, upravljati glasnoćom i svjetlinom, izrađivati snimke zaslona i drugo."</string>
<string name="assistant_label" msgid="6796392082252272356">"Asistent"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Postavke pristupačnosti"</string>
@@ -20,7 +20,7 @@
<string name="brightness_down_label" msgid="7115662941913272072">"Smanji svjetlinu"</string>
<string name="previous_button_content_description" msgid="840869171117765966">"Idi na prethodni zaslon"</string>
<string name="next_button_content_description" msgid="6810058269847364406">"Idi na sljedeći zaslon"</string>
- <string name="accessibility_menu_description" msgid="4458354794093858297">"Izbornik pristupačnosti pruža velik izbornik na zaslonu u svrhu upravljanja uređajem. Možete zaključati uređaj, upravljati glasnoćom i svjetlinom, izrađivati snimke zaslona i drugo."</string>
+ <string name="accessibility_menu_description" msgid="4458354794093858297">"Izbornik pristupačnosti veliki je zaslonski izbornik koji vam omogućuje upravljanje uređajem. Putem njega možete zaključati uređaj, upravljati glasnoćom i svjetlinom, izrađivati snimke zaslona i drugo."</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"Upravljanje uređajem pomoću velikog izbornika"</string>
<string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Postavke izbornika pristupačnosti"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Veliki gumbi"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml
index 38cc39505e86..d23ddcade19f 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="accessibility_menu_service_name" msgid="730136711554740131">"Erişilebilirlik menüsü"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"Erişilebilirlik menüsü, cihazınızı kontrol etmeniz için geniş bir ekran menüsü sağlar. Cihazınızı kilitleyebilir, ses düzeyini ve parlaklığı kontrol edebilir, ekran görüntüsü alabilir ve daha fazlasını yapabilirsiniz."</string>
+ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Erişilebilirlik Menüsü"</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Erişilebilirlik Menüsü, cihazınızı kontrol etmeniz için geniş bir ekran menüsü sağlar. Cihazınızı kilitleyebilir, ses düzeyini ve parlaklığı kontrol edebilir, ekran görüntüsü alabilir ve daha fazlasını yapabilirsiniz."</string>
<string name="assistant_label" msgid="6796392082252272356">"Asistan"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Asistan"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Erişebilirlik Ayarları"</string>
@@ -20,7 +20,7 @@
<string name="brightness_down_label" msgid="7115662941913272072">"Parlaklığı azalt"</string>
<string name="previous_button_content_description" msgid="840869171117765966">"Önceki ekrana git"</string>
<string name="next_button_content_description" msgid="6810058269847364406">"Sonraki ekrana git"</string>
- <string name="accessibility_menu_description" msgid="4458354794093858297">"Erişilebilirlik menüsü, cihazınızı kontrol etmeniz için geniş bir ekran menüsü sağlar. Cihazınızı kilitleyebilir, ses düzeyini ve parlaklığı kontrol edebilir, ekran görüntüsü alabilir ve daha fazlasını yapabilirsiniz."</string>
+ <string name="accessibility_menu_description" msgid="4458354794093858297">"Erişilebilirlik Menüsü, cihazınızı kontrol etmeniz için geniş bir ekran menüsü sağlar. Cihazınızı kilitleyebilir, ses düzeyini ve parlaklığı kontrol edebilir, ekran görüntüsü alabilir ve daha fazlasını yapabilirsiniz."</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"Cihazı geniş menüyle kontrol edin"</string>
<string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Erişilebilirlik Menüsü Ayarları"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Büyük düğmeler"</string>
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index fd90bd945e0a..21881f657e6d 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -171,16 +171,6 @@ flag {
}
flag {
- name: "nssl_falsing_fix"
- namespace: "systemui"
- description: "Minor touch changes to prevent falsing errors in NSSL"
- bug: "316551193"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "refactor_get_current_user"
namespace: "systemui"
description: "KeyguardUpdateMonitor.getCurrentUser() was providing outdated results."
@@ -581,6 +571,16 @@ flag {
}
flag {
+ name: "contextual_tips_assistant_dismiss_fix"
+ namespace: "systemui"
+ description: "Improve assistant dismiss signal accuracy for contextual tips."
+ bug: "334759504"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "shaderlib_loading_effect_refactor"
namespace: "systemui"
description: "Extend shader library to provide the common loading effects."
@@ -796,7 +796,7 @@ flag {
name: "dream_input_session_pilfer_once"
namespace: "systemui"
description: "Pilfer at most once per input session"
- bug: "324600132"
+ bug: "333596426"
metadata {
purpose: PURPOSE_BUGFIX
}
diff --git a/packages/SystemUI/checks/Android.bp b/packages/SystemUI/checks/Android.bp
index addcaf4f6319..04ac748d0c78 100644
--- a/packages/SystemUI/checks/Android.bp
+++ b/packages/SystemUI/checks/Android.bp
@@ -38,8 +38,9 @@ java_test_host {
defaults: ["AndroidLintCheckerTestDefaults"],
srcs: ["tests/**/*.kt"],
data: [
- ":framework",
":androidx.annotation_annotation",
+ ":dagger2",
+ ":framework",
":kotlinx-coroutines-core",
],
static_libs: [
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SingletonAndroidComponentDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SingletonAndroidComponentDetector.kt
new file mode 100644
index 000000000000..68ec1ee8af97
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SingletonAndroidComponentDetector.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.detector.api.AnnotationInfo
+import com.android.tools.lint.detector.api.AnnotationUsageInfo
+import com.android.tools.lint.detector.api.AnnotationUsageType
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UClass
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMethod
+
+/**
+ * Prevents binding Activities, Services, and BroadcastReceivers as Singletons in the Dagger graph.
+ *
+ * It is OK to mark a BroadcastReceiver as singleton as long as it is being constructed/injected and
+ * registered directly in the code. If instead it is declared in the manifest, and we let Android
+ * construct it for us, we also need to let Android destroy it for us, so don't allow marking it as
+ * singleton.
+ */
+class SingletonAndroidComponentDetector : Detector(), SourceCodeScanner {
+ override fun applicableAnnotations(): List<String> {
+ return listOf(
+ "com.android.systemui.dagger.SysUISingleton",
+ )
+ }
+
+ override fun isApplicableAnnotationUsage(type: AnnotationUsageType): Boolean =
+ type == AnnotationUsageType.DEFINITION
+
+ override fun visitAnnotationUsage(
+ context: JavaContext,
+ element: UElement,
+ annotationInfo: AnnotationInfo,
+ usageInfo: AnnotationUsageInfo
+ ) {
+ if (element !is UAnnotation) {
+ return
+ }
+
+ val parent = element.uastParent ?: return
+
+ if (isInvalidBindingMethod(parent)) {
+ context.report(
+ ISSUE,
+ element,
+ context.getLocation(element),
+ "Do not bind Activities, Services, or BroadcastReceivers as Singleton."
+ )
+ } else if (isInvalidClassDeclaration(parent)) {
+ context.report(
+ ISSUE,
+ element,
+ context.getLocation(element),
+ "Do not mark Activities or Services as Singleton."
+ )
+ }
+ }
+
+ private fun isInvalidBindingMethod(parent: UElement): Boolean {
+ if (parent !is UMethod) {
+ return false
+ }
+
+ if (
+ parent.returnType?.canonicalText !in
+ listOf(
+ "android.app.Activity",
+ "android.app.Service",
+ "android.content.BroadcastReceiver",
+ )
+ ) {
+ return false
+ }
+
+ if (
+ !MULTIBIND_ANNOTATIONS.all { it in parent.annotations.map { it.qualifiedName } } &&
+ !MULTIPROVIDE_ANNOTATIONS.all { it in parent.annotations.map { it.qualifiedName } }
+ ) {
+ return false
+ }
+ return true
+ }
+
+ private fun isInvalidClassDeclaration(parent: UElement): Boolean {
+ if (parent !is UClass) {
+ return false
+ }
+
+ if (
+ parent.javaPsi.superClass?.qualifiedName !in
+ listOf(
+ "android.app.Activity",
+ "android.app.Service",
+ // Fine to mark BroadcastReceiver as singleton in this scenario
+ )
+ ) {
+ return false
+ }
+
+ return true
+ }
+
+ companion object {
+ @JvmField
+ val ISSUE: Issue =
+ Issue.create(
+ id = "SingletonAndroidComponent",
+ briefDescription = "Activity, Service, or BroadcastReceiver marked as Singleton",
+ explanation =
+ """Activities, Services, and BroadcastReceivers are created and destroyed by
+ the Android System Server. Marking them with a Dagger scope
+ results in them being cached and reused by Dagger. Trying to reuse a
+ component like this will make for a very bad time.""",
+ category = Category.CORRECTNESS,
+ priority = 10,
+ severity = Severity.ERROR,
+ moreInfo =
+ "https://developer.android.com/guide/components/activities/process-lifecycle",
+ // Note that JAVA_FILE_SCOPE also includes Kotlin source files.
+ implementation =
+ Implementation(
+ SingletonAndroidComponentDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+
+ private val MULTIBIND_ANNOTATIONS =
+ listOf("dagger.Binds", "dagger.multibindings.IntoMap", "dagger.multibindings.ClassKey")
+
+ val MULTIPROVIDE_ANNOTATIONS =
+ listOf(
+ "dagger.Provides",
+ "dagger.multibindings.IntoMap",
+ "dagger.multibindings.ClassKey"
+ )
+ }
+}
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 e93264c8e7b3..cecbc474a18a 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
@@ -40,6 +40,7 @@ class SystemUIIssueRegistry : IssueRegistry() {
RegisterReceiverViaContextDetector.ISSUE,
SoftwareBitmapDetector.ISSUE,
NonInjectedServiceDetector.ISSUE,
+ SingletonAndroidComponentDetector.ISSUE,
StaticSettingsProviderDetector.ISSUE,
DemotingTestWithoutBugDetector.ISSUE,
TestFunctionNameViolationDetector.ISSUE,
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt
index e1cca88a8fe0..8396f3fee892 100644
--- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt
@@ -21,8 +21,9 @@ import java.io.File
internal val libraryNames =
arrayOf(
- "framework.jar",
"androidx.annotation_annotation.jar",
+ "dagger2.jar",
+ "framework.jar",
"kotlinx-coroutines-core.jar",
)
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SingletonAndroidComponentDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SingletonAndroidComponentDetectorTest.kt
new file mode 100644
index 000000000000..0606af80f27a
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SingletonAndroidComponentDetectorTest.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class SingletonAndroidComponentDetectorTest : SystemUILintDetectorTest() {
+ override fun getDetector(): Detector = SingletonAndroidComponentDetector()
+
+ override fun getIssues(): List<Issue> = listOf(SingletonAndroidComponentDetector.ISSUE)
+
+ @Test
+ fun testBindsServiceAsSingleton() {
+ lint()
+ .files(
+ TestFiles.kotlin(
+ """
+ package test.pkg
+
+ import android.app.Service
+ import com.android.systemui.dagger.SysUISingleton
+ import dagger.Binds
+ import dagger.Module
+ import dagger.multibindings.ClassKey
+ import dagger.multibindings.IntoMap
+
+ @Module
+ interface BadModule {
+ @SysUISingleton
+ @Binds
+ @IntoMap
+ @ClassKey(SingletonService::class)
+ fun bindSingletonService(service: SingletonService): Service
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs
+ )
+ .issues(SingletonAndroidComponentDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/test/pkg/BadModule.kt:12: Error: Do not bind Activities, Services, or BroadcastReceivers as Singleton. [SingletonAndroidComponent]
+ @SysUISingleton
+ ~~~~~~~~~~~~~~~
+ 1 errors, 0 warnings
+ """
+ .trimIndent()
+ )
+ }
+
+ @Test
+ fun testProvidesBroadcastReceiverAsSingleton() {
+ lint()
+ .files(
+ TestFiles.kotlin(
+ """
+ package test.pkg
+
+ import android.content.BroadcastReceiver
+ import com.android.systemui.dagger.SysUISingleton
+ import dagger.Provides
+ import dagger.Module
+ import dagger.multibindings.ClassKey
+ import dagger.multibindings.IntoMap
+
+ @Module
+ abstract class BadModule {
+ @SysUISingleton
+ @Provides
+ @IntoMap
+ @ClassKey(SingletonBroadcastReceiver::class)
+ fun providesSingletonBroadcastReceiver(br: SingletonBroadcastReceiver): BroadcastReceiver {
+ return br
+ }
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs
+ )
+ .issues(SingletonAndroidComponentDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/test/pkg/BadModule.kt:12: Error: Do not bind Activities, Services, or BroadcastReceivers as Singleton. [SingletonAndroidComponent]
+ @SysUISingleton
+ ~~~~~~~~~~~~~~~
+ 1 errors, 0 warnings
+ """
+ .trimIndent()
+ )
+ }
+ @Test
+ fun testMarksActivityAsSingleton() {
+ lint()
+ .files(
+ TestFiles.kotlin(
+ """
+ package test.pkg
+
+ import android.app.Activity
+ import com.android.systemui.dagger.SysUISingleton
+
+ @SysUISingleton
+ class BadActivity : Activity() {
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs
+ )
+ .issues(SingletonAndroidComponentDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/test/pkg/BadActivity.kt:6: Error: Do not mark Activities or Services as Singleton. [SingletonAndroidComponent]
+ @SysUISingleton
+ ~~~~~~~~~~~~~~~
+ 1 errors, 0 warnings
+ """
+ .trimIndent()
+ )
+ }
+ @Test
+ fun testMarksBroadcastReceiverAsSingleton() {
+ lint()
+ .files(
+ TestFiles.kotlin(
+ """
+ package test.pkg
+
+ import android.content.BroadcastReceiver
+ import com.android.systemui.dagger.SysUISingleton
+
+ @SysUISingleton
+ class SingletonReceveiver : BroadcastReceiver() {
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs
+ )
+ .issues(SingletonAndroidComponentDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ // Define stubs for Android imports. The tests don't run on Android so
+ // they don't "see" any of Android specific classes. We need to define
+ // the method parameters for proper resolution.
+ private val singletonStub: TestFile =
+ java(
+ """
+ package com.android.systemui.dagger;
+
+ public @interface SysUISingleton {
+ }
+ """
+ )
+
+ private val stubs = arrayOf(singletonStub) + androidStubs
+}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
new file mode 100644
index 000000000000..3d7401d8f263
--- /dev/null
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene
+
+import com.android.systemui.qs.ui.composable.QuickSettingsShadeScene
+import com.android.systemui.scene.shared.model.Scene
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+
+@Module
+interface QuickSettingsShadeSceneModule {
+
+ @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
index 2ba78cfd7785..fdf82ca026b1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
@@ -30,11 +30,15 @@ import com.android.compose.nestedscroll.PriorityNestedScrollConnection
*/
fun NotificationScrimNestedScrollConnection(
scrimOffset: () -> Float,
- onScrimOffsetChanged: (Float) -> Unit,
+ snapScrimOffset: (Float) -> Unit,
+ animateScrimOffset: (Float) -> Unit,
minScrimOffset: () -> Float,
maxScrimOffset: Float,
contentHeight: () -> Float,
minVisibleScrimHeight: () -> Float,
+ isCurrentGestureOverscroll: () -> Boolean,
+ onStart: (Float) -> Unit = {},
+ onStop: (Float) -> Unit = {},
): PriorityNestedScrollConnection {
return PriorityNestedScrollConnection(
orientation = Orientation.Vertical,
@@ -49,7 +53,7 @@ fun NotificationScrimNestedScrollConnection(
// scrolling down and content is done scrolling to top. After that, the scrim
// needs to collapse; collapse the scrim until it is at the maxScrimOffset.
canStartPostScroll = { offsetAvailable, _ ->
- offsetAvailable > 0 && scrimOffset() < maxScrimOffset
+ offsetAvailable > 0 && (scrimOffset() < maxScrimOffset || isCurrentGestureOverscroll())
},
canStartPostFling = { false },
canContinueScroll = {
@@ -57,7 +61,7 @@ fun NotificationScrimNestedScrollConnection(
minScrimOffset() < currentHeight && currentHeight < maxScrimOffset
},
canScrollOnFling = true,
- onStart = { /* do nothing */},
+ onStart = { offsetAvailable -> onStart(offsetAvailable) },
onScroll = { offsetAvailable ->
val currentHeight = scrimOffset()
val amountConsumed =
@@ -68,10 +72,16 @@ fun NotificationScrimNestedScrollConnection(
val amountLeft = minScrimOffset() - currentHeight
offsetAvailable.coerceAtLeast(amountLeft)
}
- onScrimOffsetChanged(currentHeight + amountConsumed)
+ snapScrimOffset(currentHeight + amountConsumed)
amountConsumed
},
// Don't consume the velocity on pre/post fling
- onStop = { 0f },
+ onStop = { velocityAvailable ->
+ onStop(velocityAvailable)
+ if (scrimOffset() < minScrimOffset()) {
+ animateScrimOffset(minScrimOffset())
+ }
+ 0f
+ },
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 6e987bd03483..3ce0feb0af56 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -18,6 +18,8 @@
package com.android.systemui.notifications.ui.composable
import android.util.Log
+import androidx.compose.animation.core.Animatable
+import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.Box
@@ -29,7 +31,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
-import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
@@ -39,8 +40,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -69,6 +69,8 @@ import com.android.compose.modifiers.height
import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
import com.android.systemui.res.R
+import com.android.systemui.scene.session.ui.composable.SaveableSession
+import com.android.systemui.scene.session.ui.composable.rememberSession
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.composable.ShadeHeader
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
@@ -77,6 +79,7 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.Notificati
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_MAX_SCRIM_ALPHA
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import kotlin.math.roundToInt
+import kotlinx.coroutines.launch
object Notifications {
object Elements {
@@ -154,16 +157,22 @@ fun SceneScope.ConstrainedNotificationStack(
*/
@Composable
fun SceneScope.NotificationScrollingStack(
+ shadeSession: SaveableSession,
viewModel: NotificationsPlaceholderViewModel,
maxScrimTop: () -> Float,
shouldPunchHoleBehindScrim: Boolean,
modifier: Modifier = Modifier,
) {
+ val coroutineScope = rememberCoroutineScope()
val density = LocalDensity.current
val screenCornerRadius = LocalScreenCornerRadius.current
val scrimCornerRadius = dimensionResource(R.dimen.notification_scrim_corner_radius)
- val scrollState = rememberScrollState()
+ val scrollState =
+ shadeSession.rememberSaveableSession(saver = ScrollState.Saver, key = null) {
+ ScrollState(initial = 0)
+ }
val syntheticScroll = viewModel.syntheticScroll.collectAsState(0f)
+ val isCurrentGestureOverscroll = viewModel.isCurrentGestureOverscroll.collectAsState(false)
val expansionFraction by viewModel.expandFraction.collectAsState(0f)
val navBarHeight =
@@ -180,7 +189,7 @@ fun SceneScope.NotificationScrollingStack(
// When fully expanded (scrimOffset = minScrimOffset), its top bound is at minScrimStartY,
// which is equal to the height of the Shade Header. Thus, when the scrim is fully expanded, the
// entire height of the scrim is visible on screen.
- val scrimOffset = remember { mutableStateOf(0f) }
+ val scrimOffset = shadeSession.rememberSession { Animatable(0f) }
// set the bounds to null when the scrim disappears
DisposableEffect(Unit) { onDispose { viewModel.onScrimBoundsChanged(null) } }
@@ -204,7 +213,7 @@ fun SceneScope.NotificationScrollingStack(
// expanded, reset scrim offset.
LaunchedEffect(stackHeight, scrimOffset) {
snapshotFlow { stackHeight.value < minVisibleScrimHeight() && scrimOffset.value < 0f }
- .collect { shouldCollapse -> if (shouldCollapse) scrimOffset.value = 0f }
+ .collect { shouldCollapse -> if (shouldCollapse) scrimOffset.snapTo(0f) }
}
// if we receive scroll delta from NSSL, offset the scrim and placeholder accordingly.
@@ -214,7 +223,7 @@ fun SceneScope.NotificationScrollingStack(
val minOffset = minScrimOffset()
if (scrimOffset.value > minOffset) {
val remainingDelta = (minOffset - (scrimOffset.value - delta)).coerceAtLeast(0f)
- scrimOffset.value = (scrimOffset.value - delta).coerceAtLeast(minOffset)
+ scrimOffset.snapTo((scrimOffset.value - delta).coerceAtLeast(minOffset))
if (remainingDelta > 0f) {
scrollState.scrollBy(remainingDelta)
}
@@ -296,20 +305,30 @@ fun SceneScope.NotificationScrollingStack(
modifier =
Modifier.verticalNestedScrollToScene(
topBehavior = NestedScrollBehavior.EdgeWithPreview,
+ isExternalOverscrollGesture = { isCurrentGestureOverscroll.value }
)
.nestedScroll(
- remember(
+ shadeSession.rememberSession(
scrimOffset,
maxScrimTop,
minScrimTop,
+ isCurrentGestureOverscroll,
) {
NotificationScrimNestedScrollConnection(
scrimOffset = { scrimOffset.value },
- onScrimOffsetChanged = { scrimOffset.value = it },
+ snapScrimOffset = { value ->
+ coroutineScope.launch { scrimOffset.snapTo(value) }
+ },
+ animateScrimOffset = { value ->
+ coroutineScope.launch { scrimOffset.animateTo(value) }
+ },
minScrimOffset = minScrimOffset,
maxScrimOffset = 0f,
contentHeight = { stackHeight.value },
minVisibleScrimHeight = minVisibleScrimHeight,
+ isCurrentGestureOverscroll = {
+ isCurrentGestureOverscroll.value
+ },
)
}
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
index 1f0340805c95..1c675e339941 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
@@ -26,10 +26,10 @@ import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeSceneViewModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.ui.composable.OverlayShade
-import com.android.systemui.shade.ui.viewmodel.NotificationsShadeSceneViewModel
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeSessionModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeSessionModule.kt
new file mode 100644
index 000000000000..076c9177138b
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeSessionModule.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.notifications.ui.composable
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.saveable.Saver
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.session.shared.SessionStorage
+import com.android.systemui.scene.session.ui.composable.SaveableSession
+import com.android.systemui.scene.session.ui.composable.Session
+import dagger.Module
+import dagger.Provides
+
+@Module
+object NotificationsShadeSessionModule {
+ @Provides @SysUISingleton fun provideShadeSessionStorage(): SessionStorage = SessionStorage()
+
+ @Provides
+ fun provideShadeSession(storage: SessionStorage): SaveableSession =
+ object : SaveableSession, Session by Session(storage) {
+ @Composable
+ override fun <T : Any> rememberSaveableSession(
+ vararg inputs: Any?,
+ saver: Saver<T, out Any>,
+ key: String?,
+ init: () -> T
+ ): T = rememberSession(key, inputs = inputs, init = init)
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 4c0f2e11f76f..ec9136d50e4c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -80,6 +80,7 @@ import com.android.systemui.notifications.ui.composable.NotificationScrollingSta
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.res.R
+import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
@@ -103,6 +104,7 @@ class QuickSettingsScene
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
+ private val shadeSession: SaveableSession,
private val viewModel: QuickSettingsSceneViewModel,
private val notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel,
private val tintedIconManagerFactory: TintedIconManager.Factory,
@@ -133,6 +135,7 @@ constructor(
mediaCarouselController = mediaCarouselController,
mediaHost = mediaHost,
modifier = modifier,
+ shadeSession = shadeSession,
)
}
}
@@ -147,6 +150,7 @@ private fun SceneScope.QuickSettingsScene(
mediaCarouselController: MediaCarouselController,
mediaHost: MediaHost,
modifier: Modifier = Modifier,
+ shadeSession: SaveableSession,
) {
val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState()
val contentAlpha by
@@ -347,6 +351,7 @@ private fun SceneScope.QuickSettingsScene(
}
NotificationScrollingStack(
viewModel = notificationsPlaceholderViewModel,
+ shadeSession = shadeSession,
maxScrimTop = { screenHeight },
shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
modifier =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
new file mode 100644
index 000000000000..636c6c3b7d14
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.composable
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.ui.composable.OverlayShade
+import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+@SysUISingleton
+class QuickSettingsShadeScene
+@Inject
+constructor(
+ viewModel: QuickSettingsShadeSceneViewModel,
+ private val overlayShadeViewModel: OverlayShadeViewModel,
+) : ComposableScene {
+
+ override val key = Scenes.QuickSettingsShade
+
+ override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
+ viewModel.destinationScenes
+
+ @Composable
+ override fun SceneScope.Content(
+ modifier: Modifier,
+ ) {
+ OverlayShade(
+ viewModel = overlayShadeViewModel,
+ modifier = modifier,
+ horizontalArrangement = Arrangement.End,
+ ) {
+ Text(
+ text = "Quick settings grid",
+ modifier = Modifier.padding(QuickSettingsShade.Dimensions.Padding)
+ )
+ }
+ }
+}
+
+object QuickSettingsShade {
+ object Dimensions {
+ val Padding = 16.dp
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt
new file mode 100644
index 000000000000..dc5891915bfc
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.session.shared
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+
+/** Data store for [Session][com.android.systemui.scene.session.ui.composable.Session]. */
+class SessionStorage {
+ private var _storage by mutableStateOf(hashMapOf<String, StorageEntry>())
+
+ /**
+ * Data store containing all state retained for invocations of
+ * [rememberSession][com.android.systemui.scene.session.ui.composable.Session.rememberSession]
+ */
+ val storage: MutableMap<String, StorageEntry>
+ get() = _storage
+
+ /**
+ * Storage for an individual invocation of
+ * [rememberSession][com.android.systemui.scene.session.ui.composable.Session.rememberSession]
+ */
+ class StorageEntry(val keys: Array<out Any?>, var stored: Any?)
+
+ /** Clears the data store; any downstream usage within `@Composable`s will be recomposed. */
+ fun clear() {
+ _storage = hashMapOf()
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/ui/composable/Session.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/ui/composable/Session.kt
new file mode 100644
index 000000000000..924aa540aa7f
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/ui/composable/Session.kt
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.session.ui.composable
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.currentCompositeKeyHash
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.Saver
+import androidx.compose.runtime.saveable.SaverScope
+import androidx.compose.runtime.saveable.mapSaver
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import com.android.systemui.scene.session.shared.SessionStorage
+import com.android.systemui.util.kotlin.mapValuesNotNullTo
+
+/**
+ * An explicit storage for remembering composable state outside of the lifetime of a composition.
+ *
+ * Specifically, this allows easy conversion of standard
+ * [remember][androidx.compose.runtime.remember] invocations to ones that are preserved beyond the
+ * callsite's existence in the composition.
+ *
+ * ```kotlin
+ * @Composable
+ * fun Parent() {
+ * val session = remember { Session() }
+ * ...
+ * if (someCondition) {
+ * Child(session)
+ * }
+ * }
+ *
+ * @Composable
+ * fun Child(session: Session) {
+ * val state by session.rememberSession { mutableStateOf(0f) }
+ * ...
+ * }
+ * ```
+ */
+interface Session {
+ /**
+ * Remember the value returned by [init] if all [inputs] are equal (`==`) to the values they had
+ * in the previous composition, otherwise produce and remember a new value by calling [init].
+ *
+ * @param inputs A set of inputs such that, when any of them have changed, will cause the state
+ * to reset and [init] to be rerun
+ * @param key An optional key to be used as a key for the saved value. If `null`, we use the one
+ * automatically generated by the Compose runtime which is unique for the every exact code
+ * location in the composition tree
+ * @param init A factory function to create the initial value of this state
+ * @see androidx.compose.runtime.remember
+ */
+ @Composable fun <T> rememberSession(key: String?, vararg inputs: Any?, init: () -> T): T
+}
+
+/** Returns a new [Session], optionally backed by the provided [SessionStorage]. */
+fun Session(storage: SessionStorage = SessionStorage()): Session = SessionImpl(storage)
+
+/**
+ * Remember the value returned by [init] if all [inputs] are equal (`==`) to the values they had in
+ * the previous composition, otherwise produce and remember a new value by calling [init].
+ *
+ * @param inputs A set of inputs such that, when any of them have changed, will cause the state to
+ * reset and [init] to be rerun
+ * @param key An optional key to be used as a key for the saved value. If not provided we use the
+ * one automatically generated by the Compose runtime which is unique for the every exact code
+ * location in the composition tree
+ * @param init A factory function to create the initial value of this state
+ * @see androidx.compose.runtime.remember
+ */
+@Composable
+fun <T> Session.rememberSession(vararg inputs: Any?, key: String? = null, init: () -> T): T =
+ rememberSession(key, inputs, init = init)
+
+/**
+ * An explicit storage for remembering composable state outside of the lifetime of a composition.
+ *
+ * Specifically, this allows easy conversion of standard [rememberSession] invocations to ones that
+ * are preserved beyond the callsite's existence in the composition.
+ *
+ * ```kotlin
+ * @Composable
+ * fun Parent() {
+ * val session = rememberSaveableSession()
+ * ...
+ * if (someCondition) {
+ * Child(session)
+ * }
+ * }
+ *
+ * @Composable
+ * fun Child(session: SaveableSession) {
+ * val state by session.rememberSaveableSession { mutableStateOf(0f) }
+ * ...
+ * }
+ * ```
+ */
+interface SaveableSession : Session {
+ /**
+ * Remember the value produced by [init].
+ *
+ * It behaves similarly to [rememberSession], but the stored value will survive the activity or
+ * process recreation using the saved instance state mechanism (for example it happens when the
+ * screen is rotated in the Android application).
+ *
+ * @param inputs A set of inputs such that, when any of them have changed, will cause the state
+ * to reset and [init] to be rerun
+ * @param saver The [Saver] object which defines how the state is saved and restored.
+ * @param key An optional key to be used as a key for the saved value. If not provided we use
+ * the automatically generated by the Compose runtime which is unique for the every exact code
+ * location in the composition tree
+ * @param init A factory function to create the initial value of this state
+ * @see rememberSaveable
+ */
+ @Composable
+ fun <T : Any> rememberSaveableSession(
+ vararg inputs: Any?,
+ saver: Saver<T, out Any>,
+ key: String?,
+ init: () -> T,
+ ): T
+}
+
+/**
+ * Returns a new [SaveableSession] that is preserved across configuration changes.
+ *
+ * @param inputs A set of inputs such that, when any of them have changed, will cause the state to
+ * reset.
+ * @param key An optional key to be used as a key for the saved value. If not provided we use the
+ * automatically generated by the Compose runtime which is unique for the every exact code
+ * location in the composition tree.
+ */
+@Composable
+fun rememberSaveableSession(
+ vararg inputs: Any?,
+ key: String? = null,
+): SaveableSession =
+ rememberSaveable(inputs, SaveableSessionImpl.SessionSaver, key) { SaveableSessionImpl() }
+
+private class SessionImpl(
+ private val storage: SessionStorage = SessionStorage(),
+) : Session {
+ @Composable
+ override fun <T> rememberSession(key: String?, vararg inputs: Any?, init: () -> T): T {
+ val storage = storage.storage
+ val compositeKey = currentCompositeKeyHash
+ // key is the one provided by the user or the one generated by the compose runtime
+ val finalKey =
+ if (!key.isNullOrEmpty()) {
+ key
+ } else {
+ compositeKey.toString(MAX_SUPPORTED_RADIX)
+ }
+ if (finalKey !in storage) {
+ val value = init()
+ SideEffect { storage[finalKey] = SessionStorage.StorageEntry(inputs, value) }
+ return value
+ }
+ val entry = storage[finalKey]!!
+ if (!inputs.contentEquals(entry.keys)) {
+ val value = init()
+ SideEffect { entry.stored = value }
+ return value
+ }
+ @Suppress("UNCHECKED_CAST") return entry.stored as T
+ }
+}
+
+private class SaveableSessionImpl(
+ saveableStorage: MutableMap<String, StorageEntry> = mutableMapOf(),
+ sessionStorage: SessionStorage = SessionStorage(),
+) : SaveableSession, Session by Session(sessionStorage) {
+
+ var saveableStorage: MutableMap<String, StorageEntry> by mutableStateOf(saveableStorage)
+
+ @Composable
+ override fun <T : Any> rememberSaveableSession(
+ vararg inputs: Any?,
+ saver: Saver<T, out Any>,
+ key: String?,
+ init: () -> T,
+ ): T {
+ val compositeKey = currentCompositeKeyHash
+ // key is the one provided by the user or the one generated by the compose runtime
+ val finalKey =
+ if (!key.isNullOrEmpty()) {
+ key
+ } else {
+ compositeKey.toString(MAX_SUPPORTED_RADIX)
+ }
+
+ @Suppress("UNCHECKED_CAST") (saver as Saver<T, Any>)
+
+ if (finalKey !in saveableStorage) {
+ val value = init()
+ SideEffect { saveableStorage[finalKey] = StorageEntry.Restored(inputs, value, saver) }
+ return value
+ }
+ when (val entry = saveableStorage[finalKey]!!) {
+ is StorageEntry.Unrestored -> {
+ val value = saver.restore(entry.unrestored) ?: init()
+ SideEffect {
+ saveableStorage[finalKey] = StorageEntry.Restored(inputs, value, saver)
+ }
+ return value
+ }
+ is StorageEntry.Restored<*> -> {
+ if (!inputs.contentEquals(entry.inputs)) {
+ val value = init()
+ SideEffect {
+ saveableStorage[finalKey] = StorageEntry.Restored(inputs, value, saver)
+ }
+ return value
+ }
+ @Suppress("UNCHECKED_CAST") return entry.stored as T
+ }
+ }
+ }
+
+ sealed class StorageEntry {
+ class Unrestored(val unrestored: Any) : StorageEntry()
+
+ class Restored<T>(val inputs: Array<out Any?>, var stored: T, val saver: Saver<T, Any>) :
+ StorageEntry() {
+ fun SaverScope.saveEntry() {
+ with(saver) { stored?.let { save(it) } }
+ }
+ }
+ }
+
+ object SessionSaver :
+ Saver<SaveableSessionImpl, Any> by mapSaver(
+ save = { sessionScope: SaveableSessionImpl ->
+ sessionScope.saveableStorage.mapValues { (k, v) ->
+ when (v) {
+ is StorageEntry.Unrestored -> v.unrestored
+ is StorageEntry.Restored<*> -> {
+ with(v) { saveEntry() }
+ }
+ }
+ }
+ },
+ restore = { savedMap: Map<String, Any?> ->
+ SaveableSessionImpl(
+ saveableStorage =
+ savedMap.mapValuesNotNullTo(mutableMapOf()) { (k, v) ->
+ v?.let { StorageEntry.Unrestored(v) }
+ }
+ )
+ }
+ )
+}
+
+private const val MAX_SUPPORTED_RADIX = 36
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index d7b10a961f91..7eaebc21355d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -5,7 +5,6 @@ import com.android.compose.animation.scene.transitions
import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition
import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition
@@ -39,20 +38,6 @@ val SceneContainerTransitions = transitions {
from(
Scenes.Gone,
to = Scenes.Shade,
- key = CollapseShadeInstantly,
- ) {
- goneToShadeTransition(durationScale = 0.0)
- }
- from(
- Scenes.Gone,
- to = Scenes.QuickSettings,
- key = CollapseShadeInstantly,
- ) {
- goneToQuickSettingsTransition(durationScale = 0.0)
- }
- from(
- Scenes.Gone,
- to = Scenes.Shade,
key = SlightlyFasterShadeCollapse,
) {
goneToShadeTransition(durationScale = 0.9)
@@ -64,13 +49,6 @@ val SceneContainerTransitions = transitions {
from(
Scenes.Lockscreen,
to = Scenes.Shade,
- key = CollapseShadeInstantly,
- ) {
- lockscreenToShadeTransition(durationScale = 0.0)
- }
- from(
- Scenes.Lockscreen,
- to = Scenes.Shade,
key = SlightlyFasterShadeCollapse,
) {
lockscreenToShadeTransition(durationScale = 0.9)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
index 05f8f4b38176..4b4b7ed33458 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
@@ -62,4 +62,10 @@ class SceneTransitionLayoutDataSource(
coroutineScope = coroutineScope,
)
}
+
+ override fun snapToScene(toScene: SceneKey) {
+ state.snapToScene(
+ scene = toScene,
+ )
+ }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index ef5d4e1c30a6..4ad8b9f47f70 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -79,6 +79,7 @@ import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibi
import com.android.systemui.qs.ui.composable.BrightnessMirror
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.res.R
+import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.shared.model.ShadeMode
@@ -119,6 +120,7 @@ object Shade {
class ShadeScene
@Inject
constructor(
+ private val shadeSession: SaveableSession,
private val viewModel: ShadeSceneViewModel,
private val tintedIconManagerFactory: TintedIconManager.Factory,
private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
@@ -126,6 +128,7 @@ constructor(
private val mediaCarouselController: MediaCarouselController,
@Named(QUICK_QS_PANEL) private val mediaHost: MediaHost,
) : ComposableScene {
+
override val key = Scenes.Shade
override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
@@ -143,6 +146,7 @@ constructor(
mediaCarouselController = mediaCarouselController,
mediaHost = mediaHost,
modifier = modifier,
+ shadeSession = shadeSession,
)
init {
@@ -161,6 +165,7 @@ private fun SceneScope.ShadeScene(
mediaCarouselController: MediaCarouselController,
mediaHost: MediaHost,
modifier: Modifier = Modifier,
+ shadeSession: SaveableSession,
) {
val shadeMode by viewModel.shadeMode.collectAsState()
when (shadeMode) {
@@ -173,6 +178,7 @@ private fun SceneScope.ShadeScene(
mediaCarouselController = mediaCarouselController,
mediaHost = mediaHost,
modifier = modifier,
+ shadeSession = shadeSession,
)
is ShadeMode.Split ->
SplitShade(
@@ -183,6 +189,7 @@ private fun SceneScope.ShadeScene(
mediaCarouselController = mediaCarouselController,
mediaHost = mediaHost,
modifier = modifier,
+ shadeSession = shadeSession,
)
is ShadeMode.Dual -> error("Dual shade is not yet implemented!")
}
@@ -197,6 +204,7 @@ private fun SceneScope.SingleShade(
mediaCarouselController: MediaCarouselController,
mediaHost: MediaHost,
modifier: Modifier = Modifier,
+ shadeSession: SaveableSession,
) {
val maxNotifScrimTop = remember { mutableStateOf(0f) }
val tileSquishiness by
@@ -268,6 +276,7 @@ private fun SceneScope.SingleShade(
},
{
NotificationScrollingStack(
+ shadeSession = shadeSession,
viewModel = viewModel.notifications,
maxScrimTop = { maxNotifScrimTop.value },
shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
@@ -301,6 +310,7 @@ private fun SceneScope.SplitShade(
mediaCarouselController: MediaCarouselController,
mediaHost: MediaHost,
modifier: Modifier = Modifier,
+ shadeSession: SaveableSession,
) {
val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
@@ -450,6 +460,7 @@ private fun SceneScope.SplitShade(
}
NotificationScrollingStack(
+ shadeSession = shadeSession,
viewModel = viewModel.notifications,
maxScrimTop = { 0f },
shouldPunchHoleBehindScrim = false,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
index 00225fc3577a..79d17efcacc1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
@@ -16,6 +16,7 @@
package com.android.systemui.volume.panel.component.anc.ui.composable
+import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@@ -35,7 +36,6 @@ import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel
@@ -54,6 +54,13 @@ constructor(
override fun VolumePanelComposeScope.Content(modifier: Modifier) {
val slice by viewModel.buttonSlice.collectAsState()
val label = stringResource(R.string.volume_panel_noise_control_title)
+ val isClickable = viewModel.isClickable(slice)
+ val onClick =
+ if (isClickable) {
+ { ancPopup.show(null) }
+ } else {
+ null
+ }
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(12.dp),
@@ -69,15 +76,15 @@ constructor(
}
.clip(RoundedCornerShape(28.dp)),
slice = slice,
+ isEnabled = onClick != null,
onWidthChanged = viewModel::onButtonSliceWidthChanged,
- onClick = { ancPopup.show(null) }
+ onClick = onClick,
)
Text(
- modifier = Modifier.clearAndSetSemantics {},
+ modifier = Modifier.clearAndSetSemantics {}.basicMarquee(),
text = label,
style = MaterialTheme.typography.labelMedium,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
+ maxLines = 2,
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
index 74af3ca19266..fc5d212a0be7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
@@ -32,6 +32,7 @@ import com.android.systemui.res.R
fun SliceAndroidView(
slice: Slice?,
modifier: Modifier = Modifier,
+ isEnabled: Boolean = true,
onWidthChanged: ((Int) -> Unit)? = null,
onClick: (() -> Unit)? = null,
) {
@@ -40,7 +41,6 @@ fun SliceAndroidView(
factory = { context: Context ->
ClickableSliceView(
ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel),
- onClick,
)
.apply {
mode = SliceView.MODE_LARGE
@@ -50,12 +50,14 @@ fun SliceAndroidView(
if (onWidthChanged != null) {
addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged))
}
- if (onClick != null) {
- setOnClickListener { onClick() }
- }
}
},
- update = { sliceView: SliceView -> sliceView.slice = slice }
+ update = { sliceView: ClickableSliceView ->
+ sliceView.slice = slice
+ sliceView.onClick = onClick
+ sliceView.isEnabled = isEnabled
+ sliceView.isClickable = isEnabled
+ }
)
}
@@ -86,10 +88,9 @@ class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) :
* first.
*/
@SuppressLint("ViewConstructor") // only used in this class
-private class ClickableSliceView(
- context: Context,
- private val onClick: (() -> Unit)?,
-) : SliceView(context) {
+private class ClickableSliceView(context: Context) : SliceView(context) {
+
+ var onClick: (() -> Unit)? = null
init {
if (onClick != null) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
index 874c0a299d2b..12debbc9c011 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -19,6 +19,7 @@ package com.android.systemui.volume.panel.component.button.ui.composable
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@@ -91,7 +92,8 @@ class ToggleButtonComponent(
},
onClick = { onCheckedChange(!viewModel.isActive) },
shape = RoundedCornerShape(28.dp),
- colors = colors
+ colors = colors,
+ contentPadding = PaddingValues(0.dp)
) {
Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
index c51e8b0ead12..a602e25e05c1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
@@ -28,7 +28,11 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.paneTitle
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
+import com.android.systemui.res.R
import com.android.systemui.volume.panel.ui.layout.ComponentsLayout
import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
@@ -49,6 +53,7 @@ fun VolumePanelRoot(
}
}
+ val accessibilityTitle = stringResource(R.string.accessibility_volume_settings)
val state: VolumePanelState by viewModel.volumePanelState.collectAsState()
val components by viewModel.componentsLayout.collectAsState(null)
@@ -56,12 +61,14 @@ fun VolumePanelRoot(
components?.let { componentsState ->
Components(
componentsState,
- modifier.padding(
- start = padding,
- top = padding,
- end = padding,
- bottom = 20.dp,
- )
+ modifier
+ .semantics { paneTitle = accessibilityTitle }
+ .padding(
+ start = padding,
+ top = padding,
+ end = padding,
+ bottom = 20.dp,
+ )
)
}
}
diff --git a/packages/SystemUI/compose/scene/OWNERS b/packages/SystemUI/compose/scene/OWNERS
index 33a59c2bcab3..dac37eeb3e8c 100644
--- a/packages/SystemUI/compose/scene/OWNERS
+++ b/packages/SystemUI/compose/scene/OWNERS
@@ -2,12 +2,13 @@ set noparent
# Bug component: 1184816
+amiko@google.com
jdemeulenaere@google.com
omarmt@google.com
# SysUI Dr No's.
# Don't send reviews here.
-dsandler@android.com
cinek@google.com
+dsandler@android.com
juliacr@google.com
pixel@google.com \ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 6b289f3c66a3..b5e93131f828 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -47,8 +47,11 @@ internal fun CoroutineScope.animateToScene(
}
return when (transitionState) {
- is TransitionState.Idle -> animate(layoutState, target, transitionKey)
+ is TransitionState.Idle ->
+ animate(layoutState, target, transitionKey, isInitiatedByUserInput = false)
is TransitionState.Transition -> {
+ val isInitiatedByUserInput = transitionState.isInitiatedByUserInput
+
// A transition is currently running: first check whether `transition.toScene` or
// `transition.fromScene` is the same as our target scene, in which case the transition
// can be accelerated or reversed to end up in the target state.
@@ -68,8 +71,14 @@ internal fun CoroutineScope.animateToScene(
} else {
// The transition is in progress: start the canned animation at the same
// progress as it was in.
- // TODO(b/290184746): Also take the current velocity into account.
- animate(layoutState, target, transitionKey, startProgress = progress)
+ animate(
+ layoutState,
+ target,
+ transitionKey,
+ isInitiatedByUserInput,
+ initialProgress = progress,
+ initialVelocity = transitionState.progressVelocity,
+ )
}
} else if (transitionState.fromScene == target) {
// There is a transition from [target] to another scene: simply animate the same
@@ -83,19 +92,52 @@ internal fun CoroutineScope.animateToScene(
layoutState.finishTransition(transitionState, target)
null
} else {
- // TODO(b/290184746): Also take the current velocity into account.
animate(
layoutState,
target,
transitionKey,
- startProgress = progress,
+ isInitiatedByUserInput,
+ initialProgress = progress,
+ initialVelocity = transitionState.progressVelocity,
reversed = true,
)
}
} else {
// Generic interruption; the current transition is neither from or to [target].
- // TODO(b/290930950): Better handle interruptions here.
- animate(layoutState, target, transitionKey)
+ val interruptionResult =
+ layoutState.transitions.interruptionHandler.onInterruption(
+ transitionState,
+ target,
+ )
+ ?: DefaultInterruptionHandler.onInterruption(transitionState, target)
+
+ val animateFrom = interruptionResult.animateFrom
+ if (
+ animateFrom != transitionState.toScene &&
+ animateFrom != transitionState.fromScene
+ ) {
+ error(
+ "InterruptionResult.animateFrom must be either the fromScene " +
+ "(${transitionState.fromScene.debugName}) or the toScene " +
+ "(${transitionState.toScene.debugName}) of the interrupted transition."
+ )
+ }
+
+ // If we were A => B and that we are now animating A => C, add a transition B => A
+ // to the list of transitions so that B "disappears back to A".
+ val chain = interruptionResult.chain
+ if (chain && animateFrom != transitionState.currentScene) {
+ animateToScene(layoutState, animateFrom, transitionKey = null)
+ }
+
+ animate(
+ layoutState,
+ target,
+ transitionKey,
+ isInitiatedByUserInput,
+ fromScene = animateFrom,
+ chain = chain,
+ )
}
}
}
@@ -103,32 +145,31 @@ internal fun CoroutineScope.animateToScene(
private fun CoroutineScope.animate(
layoutState: BaseSceneTransitionLayoutState,
- target: SceneKey,
+ targetScene: SceneKey,
transitionKey: TransitionKey?,
- startProgress: Float = 0f,
+ isInitiatedByUserInput: Boolean,
+ initialProgress: Float = 0f,
+ initialVelocity: Float = 0f,
reversed: Boolean = false,
+ fromScene: SceneKey = layoutState.transitionState.currentScene,
+ chain: Boolean = true,
): TransitionState.Transition {
- val fromScene = layoutState.transitionState.currentScene
- val isUserInput =
- (layoutState.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
- ?: false
-
val targetProgress = if (reversed) 0f else 1f
val transition =
if (reversed) {
OneOffTransition(
- fromScene = target,
+ fromScene = targetScene,
toScene = fromScene,
- currentScene = target,
- isInitiatedByUserInput = isUserInput,
+ currentScene = targetScene,
+ isInitiatedByUserInput = isInitiatedByUserInput,
isUserInputOngoing = false,
)
} else {
OneOffTransition(
fromScene = fromScene,
- toScene = target,
- currentScene = target,
- isInitiatedByUserInput = isUserInput,
+ toScene = targetScene,
+ currentScene = targetScene,
+ isInitiatedByUserInput = isInitiatedByUserInput,
isUserInputOngoing = false,
)
}
@@ -136,7 +177,7 @@ private fun CoroutineScope.animate(
// Change the current layout state to start this new transition. This will compute the
// TransformationSpec associated to this transition, which we need to initialize the Animatable
// that will actually animate it.
- layoutState.startTransition(transition, transitionKey)
+ layoutState.startTransition(transition, transitionKey, chain)
// The transition now contains the transformation spec that we should use to instantiate the
// Animatable.
@@ -144,19 +185,19 @@ private fun CoroutineScope.animate(
val visibilityThreshold =
(animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
val animatable =
- Animatable(startProgress, visibilityThreshold = visibilityThreshold).also {
+ Animatable(initialProgress, visibilityThreshold = visibilityThreshold).also {
transition.animatable = it
}
// Animate the progress to its target value.
transition.job =
- launch { animatable.animateTo(targetProgress, animationSpec) }
+ launch { animatable.animateTo(targetProgress, animationSpec, initialVelocity) }
.apply {
invokeOnCompletion {
// Settle the state to Idle(target). Note that this will do nothing if this
// transition was replaced/interrupted by another one, and this also runs if
// this coroutine is cancelled, i.e. if [this] coroutine scope is cancelled.
- layoutState.finishTransition(transition, target)
+ layoutState.finishTransition(transition, targetScene)
}
}
@@ -185,6 +226,9 @@ private class OneOffTransition(
override val progress: Float
get() = animatable.value
+ override val progressVelocity: Float
+ get() = animatable.velocity
+
override fun finish(): Job = job
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index f78ed2fdcaf6..67589909ac03 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -579,6 +579,18 @@ private class SwipeTransition(
return offset / distance
}
+ override val progressVelocity: Float
+ get() {
+ val animatable = offsetAnimation?.animatable ?: return 0f
+ val distance = distance()
+ if (distance == DistanceUnspecified) {
+ return 0f
+ }
+
+ val velocityInDistanceUnit = animatable.velocity
+ return velocityInDistanceUnit / distance.absoluteValue
+ }
+
override val isInitiatedByUserInput = true
override var bouncingScene: SceneKey? = null
@@ -865,6 +877,7 @@ internal class NestedScrollHandlerImpl(
private val orientation: Orientation,
private val topOrLeftBehavior: NestedScrollBehavior,
private val bottomOrRightBehavior: NestedScrollBehavior,
+ private val isExternalOverscrollGesture: () -> Boolean,
) {
private val layoutState = layoutImpl.state
private val draggableHandler = layoutImpl.draggableHandler(orientation)
@@ -920,7 +933,8 @@ internal class NestedScrollHandlerImpl(
return PriorityNestedScrollConnection(
orientation = orientation,
canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
- canChangeScene = offsetBeforeStart == 0f
+ canChangeScene =
+ if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f
val canInterceptSwipeTransition =
canChangeScene &&
@@ -950,7 +964,8 @@ internal class NestedScrollHandlerImpl(
else -> return@PriorityNestedScrollConnection false
}
- val isZeroOffset = offsetBeforeStart == 0f
+ val isZeroOffset =
+ if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f
val canStart =
when (behavior) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index ca643231e874..20742ee77fff 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -329,10 +329,9 @@ private fun elementTransition(
if (transition == null && previousTransition != null) {
// The transition was just finished.
- element.sceneStates.values.forEach { sceneState ->
- sceneState.offsetInterruptionDelta = Offset.Zero
- sceneState.scaleInterruptionDelta = Scale.Zero
- sceneState.alphaInterruptionDelta = 0f
+ element.sceneStates.values.forEach {
+ it.clearValuesBeforeInterruption()
+ it.clearInterruptionDeltas()
}
}
@@ -375,12 +374,22 @@ private fun prepareInterruption(element: Element) {
sceneState.scaleBeforeInterruption = lastScale
sceneState.alphaBeforeInterruption = lastAlpha
- sceneState.offsetInterruptionDelta = Offset.Zero
- sceneState.scaleInterruptionDelta = Scale.Zero
- sceneState.alphaInterruptionDelta = 0f
+ sceneState.clearInterruptionDeltas()
}
}
+private fun Element.SceneState.clearInterruptionDeltas() {
+ offsetInterruptionDelta = Offset.Zero
+ scaleInterruptionDelta = Scale.Zero
+ alphaInterruptionDelta = 0f
+}
+
+private fun Element.SceneState.clearValuesBeforeInterruption() {
+ offsetBeforeInterruption = Offset.Unspecified
+ scaleBeforeInterruption = Scale.Unspecified
+ alphaBeforeInterruption = Element.AlphaUnspecified
+}
+
/**
* Compute what [value] should be if we take the
* [interruption progress][TransitionState.Transition.interruptionProgress] of [transition] into
@@ -744,7 +753,11 @@ private fun ApproachMeasureScope.place(
// No need to place the element in this scene if we don't want to draw it anyways.
if (!shouldPlaceElement(layoutImpl, scene, element, transition)) {
sceneState.lastOffset = Offset.Unspecified
- sceneState.offsetBeforeInterruption = Offset.Unspecified
+ sceneState.lastScale = Scale.Unspecified
+ sceneState.lastAlpha = Element.AlphaUnspecified
+
+ sceneState.clearValuesBeforeInterruption()
+ sceneState.clearInterruptionDeltas()
return
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt
new file mode 100644
index 000000000000..54c64fd721ec
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/InterruptionHandler.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+/**
+ * A handler to specify how a transition should be interrupted.
+ *
+ * @see DefaultInterruptionHandler
+ * @see SceneTransitionsBuilder.interruptionHandler
+ */
+interface InterruptionHandler {
+ /**
+ * This function is called when [interrupted] is interrupted: it is currently animating between
+ * [interrupted.fromScene] and [interrupted.toScene], and we will now animate to
+ * [newTargetScene].
+ *
+ * If this returns `null`, then the [default behavior][DefaultInterruptionHandler] will be used:
+ * we will animate from [interrupted.currentScene] and chaining will be enabled (see
+ * [InterruptionResult] for more information about chaining).
+ *
+ * @see InterruptionResult
+ */
+ fun onInterruption(
+ interrupted: TransitionState.Transition,
+ newTargetScene: SceneKey,
+ ): InterruptionResult?
+}
+
+/**
+ * The result of an interruption that specifies how we should handle a transition A => B now that we
+ * have to animate to C.
+ *
+ * For instance, if the interrupted transition was A => B and currentScene = B:
+ * - animateFrom = B && chain = true => there will be 2 transitions running in parallel, A => B and
+ * B => C.
+ * - animateFrom = A && chain = true => there will be 2 transitions running in parallel, B => A and
+ * A => C.
+ * - animateFrom = B && chain = false => there will be 1 transition running, B => C.
+ * - animateFrom = A && chain = false => there will be 1 transition running, A => C.
+ */
+class InterruptionResult(
+ /**
+ * The scene we should animate from when transitioning to C.
+ *
+ * Important: This **must** be either [TransitionState.Transition.fromScene] or
+ * [TransitionState.Transition.toScene] of the transition that was interrupted.
+ */
+ val animateFrom: SceneKey,
+
+ /**
+ * Whether chaining is enabled, i.e. if the new transition to C should run in parallel with the
+ * previous one(s) or if it should be the only remaining transition that is running.
+ */
+ val chain: Boolean = true,
+)
+
+/**
+ * The default interruption handler: we animate from [TransitionState.Transition.currentScene] and
+ * chaining is enabled.
+ */
+object DefaultInterruptionHandler : InterruptionHandler {
+ override fun onInterruption(
+ interrupted: TransitionState.Transition,
+ newTargetScene: SceneKey,
+ ): InterruptionResult {
+ return InterruptionResult(
+ animateFrom = interrupted.currentScene,
+ chain = true,
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 5a2f85ad163c..1fa6b3f7d6c0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -75,6 +75,7 @@ internal fun Modifier.nestedScrollToScene(
orientation: Orientation,
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
+ isExternalOverscrollGesture: () -> Boolean,
) =
this then
NestedScrollToSceneElement(
@@ -82,6 +83,7 @@ internal fun Modifier.nestedScrollToScene(
orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
private data class NestedScrollToSceneElement(
@@ -89,6 +91,7 @@ private data class NestedScrollToSceneElement(
private val orientation: Orientation,
private val topOrLeftBehavior: NestedScrollBehavior,
private val bottomOrRightBehavior: NestedScrollBehavior,
+ private val isExternalOverscrollGesture: () -> Boolean,
) : ModifierNodeElement<NestedScrollToSceneNode>() {
override fun create() =
NestedScrollToSceneNode(
@@ -96,6 +99,7 @@ private data class NestedScrollToSceneElement(
orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
override fun update(node: NestedScrollToSceneNode) {
@@ -104,6 +108,7 @@ private data class NestedScrollToSceneElement(
orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
}
@@ -121,6 +126,7 @@ private class NestedScrollToSceneNode(
orientation: Orientation,
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
+ isExternalOverscrollGesture: () -> Boolean,
) : DelegatingNode() {
private var priorityNestedScrollConnection: PriorityNestedScrollConnection =
scenePriorityNestedScrollConnection(
@@ -128,6 +134,7 @@ private class NestedScrollToSceneNode(
orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
private var nestedScrollNode: DelegatableNode =
@@ -150,6 +157,7 @@ private class NestedScrollToSceneNode(
orientation: Orientation,
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
+ isExternalOverscrollGesture: () -> Boolean,
) {
// Clean up the old nested scroll connection
priorityNestedScrollConnection.reset()
@@ -162,6 +170,7 @@ private class NestedScrollToSceneNode(
orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
nestedScrollNode =
nestedScrollModifierNode(
@@ -177,11 +186,13 @@ private fun scenePriorityNestedScrollConnection(
orientation: Orientation,
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
+ isExternalOverscrollGesture: () -> Boolean,
) =
NestedScrollHandlerImpl(
layoutImpl = layoutImpl,
orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
.connection
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
index 339868c9fbc9..6fef33c797d9 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
@@ -141,23 +141,27 @@ internal class SceneScopeImpl(
override fun Modifier.horizontalNestedScrollToScene(
leftBehavior: NestedScrollBehavior,
rightBehavior: NestedScrollBehavior,
+ isExternalOverscrollGesture: () -> Boolean,
): Modifier =
nestedScrollToScene(
layoutImpl = layoutImpl,
orientation = Orientation.Horizontal,
topOrLeftBehavior = leftBehavior,
bottomOrRightBehavior = rightBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
override fun Modifier.verticalNestedScrollToScene(
topBehavior: NestedScrollBehavior,
- bottomBehavior: NestedScrollBehavior
+ bottomBehavior: NestedScrollBehavior,
+ isExternalOverscrollGesture: () -> Boolean,
): Modifier =
nestedScrollToScene(
layoutImpl = layoutImpl,
orientation = Orientation.Vertical,
topOrLeftBehavior = topBehavior,
bottomOrRightBehavior = bottomBehavior,
+ isExternalOverscrollGesture = isExternalOverscrollGesture,
)
override fun Modifier.noResizeDuringTransitions(): Modifier {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index c7c874c1185d..11e711ace971 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -250,6 +250,7 @@ interface BaseSceneScope : ElementStateScope {
fun Modifier.horizontalNestedScrollToScene(
leftBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
rightBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ isExternalOverscrollGesture: () -> Boolean = { false },
): Modifier
/**
@@ -262,6 +263,7 @@ interface BaseSceneScope : ElementStateScope {
fun Modifier.verticalNestedScrollToScene(
topBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
bottomBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ isExternalOverscrollGesture: () -> Boolean = { false },
): Modifier
/**
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 5fda77a3e0ae..4e3a03293796 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -117,6 +117,9 @@ sealed interface MutableSceneTransitionLayoutState : SceneTransitionLayoutState
coroutineScope: CoroutineScope,
transitionKey: TransitionKey? = null,
): TransitionState.Transition?
+
+ /** Immediately snap to the given [scene]. */
+ fun snapToScene(scene: SceneKey)
}
/**
@@ -227,6 +230,9 @@ sealed interface TransitionState {
*/
abstract val progress: Float
+ /** The current velocity of [progress], in progress units. */
+ abstract val progressVelocity: Float
+
/** Whether the transition was triggered by user input rather than being programmatic. */
abstract val isInitiatedByUserInput: Boolean
@@ -422,13 +428,18 @@ internal abstract class BaseSceneTransitionLayoutState(
}
/**
- * Start a new [transition], instantly interrupting any ongoing transition if there was one.
+ * Start a new [transition].
+ *
+ * If [chain] is `true`, then the transitions will simply be added to [currentTransitions] and
+ * will run in parallel to the current transitions. If [chain] is `false`, then the list of
+ * [currentTransitions] will be cleared and [transition] will be the only running transition.
*
* Important: you *must* call [finishTransition] once the transition is finished.
*/
internal fun startTransition(
transition: TransitionState.Transition,
transitionKey: TransitionKey?,
+ chain: Boolean = true,
) {
// Compute the [TransformationSpec] when the transition starts.
val fromScene = transition.fromScene
@@ -471,26 +482,10 @@ internal abstract class BaseSceneTransitionLayoutState(
finishTransition(currentState, currentState.currentScene)
}
- // Check that we don't have too many concurrent transitions.
- if (transitionStates.size >= MAX_CONCURRENT_TRANSITIONS) {
- Log.wtf(
- TAG,
- buildString {
- appendLine("Potential leak detected in SceneTransitionLayoutState!")
- appendLine(
- " Some transition(s) never called STLState.finishTransition()."
- )
- appendLine(" Transitions (size=${transitionStates.size}):")
- transitionStates.fastForEach { state ->
- val transition = state as TransitionState.Transition
- val from = transition.fromScene
- val to = transition.toScene
- val indicator =
- if (finishedTransitions.contains(transition)) "x" else " "
- appendLine(" [$indicator] $from => $to ($transition)")
- }
- }
- )
+ val tooManyTransitions = transitionStates.size >= MAX_CONCURRENT_TRANSITIONS
+ val clearCurrentTransitions = !chain || tooManyTransitions
+ if (clearCurrentTransitions) {
+ if (tooManyTransitions) logTooManyTransitions()
// Force finish all transitions.
while (currentTransitions.isNotEmpty()) {
@@ -511,6 +506,24 @@ internal abstract class BaseSceneTransitionLayoutState(
}
}
+ private fun logTooManyTransitions() {
+ Log.wtf(
+ TAG,
+ buildString {
+ appendLine("Potential leak detected in SceneTransitionLayoutState!")
+ appendLine(" Some transition(s) never called STLState.finishTransition().")
+ appendLine(" Transitions (size=${transitionStates.size}):")
+ transitionStates.fastForEach { state ->
+ val transition = state as TransitionState.Transition
+ val from = transition.fromScene
+ val to = transition.toScene
+ val indicator = if (finishedTransitions.contains(transition)) "x" else " "
+ appendLine(" [$indicator] $from => $to ($transition)")
+ }
+ }
+ )
+ }
+
private fun cancelActiveTransitionLinks() {
for ((link, linkedTransition) in activeTransitionLinks) {
link.target.finishTransition(linkedTransition, linkedTransition.currentScene)
@@ -735,6 +748,17 @@ internal class MutableSceneTransitionLayoutStateImpl(
override fun CoroutineScope.onChangeScene(scene: SceneKey) {
setTargetScene(scene, coroutineScope = this)
}
+
+ override fun snapToScene(scene: SceneKey) {
+ // Force finish all transitions.
+ while (currentTransitions.isNotEmpty()) {
+ val transition = transitionStates[0] as TransitionState.Transition
+ finishTransition(transition, transition.currentScene)
+ }
+
+ check(transitionStates.size == 1)
+ transitionStates[0] = TransitionState.Idle(scene)
+ }
}
private const val TAG = "SceneTransitionLayoutState"
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index b46614397ff4..0f6a1d276578 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -44,6 +44,7 @@ internal constructor(
internal val defaultSwipeSpec: SpringSpec<Float>,
internal val transitionSpecs: List<TransitionSpecImpl>,
internal val overscrollSpecs: List<OverscrollSpecImpl>,
+ internal val interruptionHandler: InterruptionHandler,
) {
private val transitionCache =
mutableMapOf<
@@ -145,6 +146,7 @@ internal constructor(
defaultSwipeSpec = DefaultSwipeSpec,
transitionSpecs = emptyList(),
overscrollSpecs = emptyList(),
+ interruptionHandler = DefaultInterruptionHandler,
)
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index 6bc397e86cfa..a4682ff2a885 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -40,6 +40,12 @@ interface SceneTransitionsBuilder {
var defaultSwipeSpec: SpringSpec<Float>
/**
+ * The [InterruptionHandler] used when transitions are interrupted. Defaults to
+ * [DefaultInterruptionHandler].
+ */
+ var interruptionHandler: InterruptionHandler
+
+ /**
* Define the default animation to be played when transitioning [to] the specified scene, from
* any scene. For the animation specification to apply only when transitioning between two
* specific scenes, use [from] instead.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 1c9080fa085d..802ab1f2eebb 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -47,12 +47,14 @@ internal fun transitionsImpl(
return SceneTransitions(
impl.defaultSwipeSpec,
impl.transitionSpecs,
- impl.transitionOverscrollSpecs
+ impl.transitionOverscrollSpecs,
+ impl.interruptionHandler,
)
}
private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
override var defaultSwipeSpec: SpringSpec<Float> = SceneTransitions.DefaultSwipeSpec
+ override var interruptionHandler: InterruptionHandler = DefaultInterruptionHandler
val transitionSpecs = mutableListOf<TransitionSpecImpl>()
val transitionOverscrollSpecs = mutableListOf<OverscrollSpecImpl>()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
index 73393a1ab0cf..79f126d24561 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt
@@ -45,5 +45,8 @@ internal class LinkedTransition(
override val progress: Float
get() = originalTransition.progress
+ override val progressVelocity: Float
+ get() = originalTransition.progressVelocity
+
override fun finish(): Job = originalTransition.finish()
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 1fd1bf4a56e2..8625482d5f71 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -32,12 +32,11 @@ import com.android.compose.animation.scene.NestedScrollBehavior.EdgeWithPreview
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
-import com.android.compose.animation.scene.TransitionState.Idle
import com.android.compose.animation.scene.TransitionState.Transition
+import com.android.compose.animation.scene.subjects.assertThat
import com.android.compose.test.MonotonicClockTestScope
import com.android.compose.test.runMonotonicClockTest
import com.google.common.truth.Truth.assertThat
-import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
@@ -103,12 +102,16 @@ class DraggableHandlerTest {
val draggableHandler = layoutImpl.draggableHandler(Orientation.Vertical)
val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal)
- fun nestedScrollConnection(nestedScrollBehavior: NestedScrollBehavior) =
+ fun nestedScrollConnection(
+ nestedScrollBehavior: NestedScrollBehavior,
+ isExternalOverscrollGesture: Boolean = false
+ ) =
NestedScrollHandlerImpl(
layoutImpl = layoutImpl,
orientation = draggableHandler.orientation,
topOrLeftBehavior = nestedScrollBehavior,
bottomOrRightBehavior = nestedScrollBehavior,
+ isExternalOverscrollGesture = { isExternalOverscrollGesture }
)
.connection
@@ -145,10 +148,8 @@ class DraggableHandlerTest {
}
fun assertIdle(currentScene: SceneKey) {
- assertThat(transitionState).isInstanceOf(Idle::class.java)
- assertWithMessage("currentScene does not match")
- .that(transitionState.currentScene)
- .isEqualTo(currentScene)
+ assertThat(transitionState).isIdle()
+ assertThat(transitionState).hasCurrentScene(currentScene)
}
fun assertTransition(
@@ -158,34 +159,12 @@ class DraggableHandlerTest {
progress: Float? = null,
isUserInputOngoing: Boolean? = null
) {
- assertThat(transitionState).isInstanceOf(Transition::class.java)
- val transition = transitionState as Transition
-
- if (currentScene != null)
- assertWithMessage("currentScene does not match")
- .that(transition.currentScene)
- .isEqualTo(currentScene)
-
- if (fromScene != null)
- assertWithMessage("fromScene does not match")
- .that(transition.fromScene)
- .isEqualTo(fromScene)
-
- if (toScene != null)
- assertWithMessage("toScene does not match")
- .that(transition.toScene)
- .isEqualTo(toScene)
-
- if (progress != null)
- assertWithMessage("progress does not match")
- .that(transition.progress)
- .isWithin(0f) // returns true when comparing 0.0f with -0.0f
- .of(progress)
-
- if (isUserInputOngoing != null)
- assertWithMessage("isUserInputOngoing does not match")
- .that(transition.isUserInputOngoing)
- .isEqualTo(isUserInputOngoing)
+ val transition = assertThat(transitionState).isTransition()
+ currentScene?.let { assertThat(transition).hasCurrentScene(it) }
+ fromScene?.let { assertThat(transition).hasFromScene(it) }
+ toScene?.let { assertThat(transition).hasToScene(it) }
+ progress?.let { assertThat(transition).hasProgress(it) }
+ isUserInputOngoing?.let { assertThat(transition).hasIsUserInputOngoing(it) }
}
fun onDragStarted(
@@ -801,6 +780,26 @@ class DraggableHandlerTest {
}
@Test
+ fun flingAfterScrollStartedByExternalOverscrollGesture() = runGestureTest {
+ val nestedScroll =
+ nestedScrollConnection(
+ nestedScrollBehavior = EdgeWithPreview,
+ isExternalOverscrollGesture = true
+ )
+
+ // scroll not consumed in child
+ nestedScroll.scroll(
+ available = downOffset(fractionOfScreen = 0.1f),
+ )
+
+ // scroll offsetY10 is all available for parents
+ nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f))
+ assertTransition(SceneA)
+
+ nestedScroll.preFling(available = Velocity(0f, velocityThreshold))
+ }
+
+ @Test
fun beforeNestedScrollStart_stop_shouldBeIgnored() = runGestureTest {
val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview)
nestedScroll.preFling(available = Velocity(0f, velocityThreshold))
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 92e1b2cd030c..e19dc965a394 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -20,7 +20,6 @@ import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
-import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.rememberScrollableState
import androidx.compose.foundation.gestures.scrollable
@@ -43,7 +42,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.layout.approachLayout
@@ -64,6 +62,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
+import com.android.compose.animation.scene.subjects.assertThat
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -78,7 +77,6 @@ class ElementTest {
@get:Rule val rule = createComposeRule()
@Composable
- @OptIn(ExperimentalComposeUiApi::class)
private fun SceneScope.Element(
key: ElementKey,
size: Dp,
@@ -496,7 +494,6 @@ class ElementTest {
}
@Test
- @OptIn(ExperimentalFoundationApi::class)
fun elementModifierNodeIsRecycledInLazyLayouts() = runTest {
val nPages = 2
val pagerState = PagerState(currentPage = 0) { nPages }
@@ -654,8 +651,7 @@ class ElementTest {
}
}
- assertThat(state.currentTransition).isNull()
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(state.transitionState).isIdle()
// Swipe by half of verticalSwipeDistance.
rule.onRoot().performTouchInput {
@@ -691,9 +687,9 @@ class ElementTest {
val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
fooElement.assertTopPositionInRootIsEqualTo(0.dp)
- val transition = state.currentTransition
+ val transition = assertThat(state.transitionState).isTransition()
assertThat(transition).isNotNull()
- assertThat(transition!!.progress).isEqualTo(0.5f)
+ assertThat(transition).hasProgress(0.5f)
assertThat(animatedFloat).isEqualTo(50f)
rule.onRoot().performTouchInput {
@@ -702,8 +698,8 @@ class ElementTest {
}
// Scroll 150% (Scene B overscroll by 50%)
- assertThat(transition.progress).isEqualTo(1.5f)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(transition).hasProgress(1.5f)
+ assertThat(transition).hasOverscrollSpec()
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
// animatedFloat cannot overflow (canOverflow = false)
assertThat(animatedFloat).isEqualTo(100f)
@@ -714,8 +710,8 @@ class ElementTest {
}
// Scroll 250% (Scene B overscroll by 150%)
- assertThat(transition.progress).isEqualTo(2.5f)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(transition).hasProgress(2.5f)
+ assertThat(transition).hasOverscrollSpec()
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
assertThat(animatedFloat).isEqualTo(100f)
}
@@ -766,8 +762,7 @@ class ElementTest {
}
}
- assertThat(state.currentTransition).isNull()
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(state.transitionState).isIdle()
val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
fooElement.assertTopPositionInRootIsEqualTo(0.dp)
@@ -779,10 +774,9 @@ class ElementTest {
moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
}
- val transition = state.currentTransition
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
- assertThat(transition).isNotNull()
- assertThat(transition!!.progress).isEqualTo(-0.5f)
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasOverscrollSpec()
+ assertThat(transition).hasProgress(-0.5f)
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
rule.onRoot().performTouchInput {
@@ -791,8 +785,8 @@ class ElementTest {
}
// Scroll 150% (Scene B overscroll by 50%)
- assertThat(transition.progress).isEqualTo(-1.5f)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(transition).hasProgress(-1.5f)
+ assertThat(transition).hasOverscrollSpec()
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
}
@@ -825,13 +819,12 @@ class ElementTest {
moveBy(Offset(0f, layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
}
- val transition = state.currentTransition
- assertThat(transition).isNotNull()
+ val transition = assertThat(state.transitionState).isTransition()
assertThat(animatedFloat).isEqualTo(100f)
// Scroll 150% (100% scroll + 50% overscroll)
- assertThat(transition!!.progress).isEqualTo(1.5f)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(transition).hasProgress(1.5f)
+ assertThat(transition).hasOverscrollSpec()
fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 0.5f)
assertThat(animatedFloat).isEqualTo(100f)
@@ -841,8 +834,8 @@ class ElementTest {
}
// Scroll 250% (100% scroll + 150% overscroll)
- assertThat(transition.progress).isEqualTo(2.5f)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(transition).hasProgress(2.5f)
+ assertThat(transition).hasOverscrollSpec()
fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 1.5f)
assertThat(animatedFloat).isEqualTo(100f)
}
@@ -882,13 +875,11 @@ class ElementTest {
moveBy(Offset(0f, layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
}
- val transition = state.currentTransition
- assertThat(transition).isNotNull()
- transition as TransitionState.HasOverscrollProperties
+ val transition = assertThat(state.transitionState).isTransition()
// Scroll 150% (100% scroll + 50% overscroll)
- assertThat(transition.progress).isEqualTo(1.5f)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(transition).hasProgress(1.5f)
+ assertThat(transition).hasOverscrollSpec()
fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * (transition.progress - 1f))
assertThat(animatedFloat).isEqualTo(100f)
@@ -900,8 +891,8 @@ class ElementTest {
rule.waitUntil(timeoutMillis = 10_000) { transition.progress < 1f }
assertThat(transition.progress).isLessThan(1f)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
- assertThat(transition.bouncingScene).isEqualTo(transition.toScene)
+ assertThat(transition).hasOverscrollSpec()
+ assertThat(transition).hasBouncingScene(transition.toScene)
assertThat(animatedFloat).isEqualTo(100f)
}
@@ -980,13 +971,13 @@ class ElementTest {
val transitions = state.currentTransitions
assertThat(transitions).hasSize(2)
- assertThat(transitions[0].fromScene).isEqualTo(SceneA)
- assertThat(transitions[0].toScene).isEqualTo(SceneB)
- assertThat(transitions[0].progress).isEqualTo(0f)
+ assertThat(transitions[0]).hasFromScene(SceneA)
+ assertThat(transitions[0]).hasToScene(SceneB)
+ assertThat(transitions[0]).hasProgress(0f)
- assertThat(transitions[1].fromScene).isEqualTo(SceneB)
- assertThat(transitions[1].toScene).isEqualTo(SceneC)
- assertThat(transitions[1].progress).isEqualTo(0f)
+ assertThat(transitions[1]).hasFromScene(SceneB)
+ assertThat(transitions[1]).hasToScene(SceneC)
+ assertThat(transitions[1]).hasProgress(0f)
// First frame: both are at x = 0dp. For the whole transition, Foo is at y = 0dp and Bar is
// at y = layoutSize - elementSoze = 100dp.
@@ -1049,24 +1040,30 @@ class ElementTest {
Box(modifier.element(TestElements.Foo).size(fooSize))
}
+ lateinit var layoutImpl: SceneTransitionLayoutImpl
rule.setContent {
- SceneTransitionLayout(state, Modifier.size(layoutSize)) {
+ SceneTransitionLayoutForTesting(
+ state,
+ Modifier.size(layoutSize),
+ onLayoutImpl = { layoutImpl = it },
+ ) {
// In scene A, Foo is aligned at the TopStart.
scene(SceneA) {
Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopStart)) }
}
+ // In scene C, Foo is aligned at the BottomEnd, so it moves vertically when coming
+ // from B. We put it before (below) scene B so that we can check that interruptions
+ // values and deltas are properly cleared once all transitions are done.
+ scene(SceneC) {
+ Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.BottomEnd)) }
+ }
+
// In scene B, Foo is aligned at the TopEnd, so it moves horizontally when coming
// from A.
scene(SceneB) {
Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopEnd)) }
}
-
- // In scene C, Foo is aligned at the BottomEnd, so it moves vertically when coming
- // from B.
- scene(SceneC) {
- Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.BottomEnd)) }
- }
}
}
@@ -1115,7 +1112,7 @@ class ElementTest {
// Interruption progress is at 100% and bToC is at 0%, so Foo should be at the same offset
// as right before the interruption.
rule
- .onNode(isElement(TestElements.Foo, SceneC))
+ .onNode(isElement(TestElements.Foo, SceneB))
.assertPositionInRootIsEqualTo(offsetInAToB.x, offsetInAToB.y)
// Move the transition forward at 30% and set the interruption progress to 50%.
@@ -1130,7 +1127,7 @@ class ElementTest {
)
rule.waitForIdle()
rule
- .onNode(isElement(TestElements.Foo, SceneC))
+ .onNode(isElement(TestElements.Foo, SceneB))
.assertPositionInRootIsEqualTo(
offsetInBToCWithInterruption.x,
offsetInBToCWithInterruption.y,
@@ -1140,7 +1137,24 @@ class ElementTest {
bToCProgress = 1f
interruptionProgress = 0f
rule
- .onNode(isElement(TestElements.Foo, SceneC))
+ .onNode(isElement(TestElements.Foo, SceneB))
.assertPositionInRootIsEqualTo(offsetInC.x, offsetInC.y)
+
+ // Manually finish the transition.
+ state.finishTransition(aToB, SceneB)
+ state.finishTransition(bToC, SceneC)
+ rule.waitForIdle()
+ assertThat(state.transitionState).isIdle()
+
+ // The interruption values should be unspecified and deltas should be set to zero.
+ val foo = layoutImpl.elements.getValue(TestElements.Foo)
+ assertThat(foo.sceneStates.keys).containsExactly(SceneC)
+ val stateInC = foo.sceneStates.getValue(SceneC)
+ assertThat(stateInC.offsetBeforeInterruption).isEqualTo(Offset.Unspecified)
+ assertThat(stateInC.scaleBeforeInterruption).isEqualTo(Scale.Unspecified)
+ assertThat(stateInC.alphaBeforeInterruption).isEqualTo(Element.AlphaUnspecified)
+ assertThat(stateInC.offsetInterruptionDelta).isEqualTo(Offset.Zero)
+ assertThat(stateInC.scaleInterruptionDelta).isEqualTo(Scale.Zero)
+ assertThat(stateInC.alphaInterruptionDelta).isEqualTo(0f)
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
new file mode 100644
index 000000000000..85d4165b4bf6
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+import androidx.compose.animation.core.tween
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestScenes.SceneA
+import com.android.compose.animation.scene.TestScenes.SceneB
+import com.android.compose.animation.scene.TestScenes.SceneC
+import com.android.compose.animation.scene.subjects.assertThat
+import com.android.compose.test.runMonotonicClockTest
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.launch
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class InterruptionHandlerTest {
+ @get:Rule val rule = createComposeRule()
+
+ @Test
+ fun default() = runMonotonicClockTest {
+ val state =
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ transitions { /* default interruption handler */},
+ )
+
+ state.setTargetScene(SceneB, coroutineScope = this)
+ state.setTargetScene(SceneC, coroutineScope = this)
+
+ assertThat(state.currentTransitions)
+ .comparingElementsUsing(FromToCurrentTriple)
+ .containsExactly(
+ // A to B.
+ Triple(SceneA, SceneB, SceneB),
+
+ // B to C.
+ Triple(SceneB, SceneC, SceneC),
+ )
+ .inOrder()
+ }
+
+ @Test
+ fun chainingDisabled() = runMonotonicClockTest {
+ val state =
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ transitions {
+ // Handler that animates from currentScene (default) but disables chaining.
+ interruptionHandler =
+ object : InterruptionHandler {
+ override fun onInterruption(
+ interrupted: TransitionState.Transition,
+ newTargetScene: SceneKey
+ ): InterruptionResult {
+ return InterruptionResult(
+ animateFrom = interrupted.currentScene,
+ chain = false,
+ )
+ }
+ }
+ },
+ )
+
+ state.setTargetScene(SceneB, coroutineScope = this)
+ state.setTargetScene(SceneC, coroutineScope = this)
+
+ assertThat(state.currentTransitions)
+ .comparingElementsUsing(FromToCurrentTriple)
+ .containsExactly(
+ // B to C.
+ Triple(SceneB, SceneC, SceneC),
+ )
+ .inOrder()
+ }
+
+ @Test
+ fun animateFromOtherScene() = runMonotonicClockTest {
+ val duration = 500
+ val state =
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ transitions {
+ // Handler that animates from the scene that is not currentScene.
+ interruptionHandler =
+ object : InterruptionHandler {
+ override fun onInterruption(
+ interrupted: TransitionState.Transition,
+ newTargetScene: SceneKey
+ ): InterruptionResult {
+ return InterruptionResult(
+ animateFrom =
+ if (interrupted.currentScene == interrupted.toScene) {
+ interrupted.fromScene
+ } else {
+ interrupted.toScene
+ }
+ )
+ }
+ }
+
+ from(SceneA, to = SceneB) { spec = tween(duration) }
+ },
+ )
+
+ // Animate to B and advance the transition a little bit so that progress > visibility
+ // threshold and that reversing from B back to A won't immediately snap to A.
+ state.setTargetScene(SceneB, coroutineScope = this)
+ testScheduler.advanceTimeBy(duration / 2L)
+
+ state.setTargetScene(SceneC, coroutineScope = this)
+
+ assertThat(state.currentTransitions)
+ .comparingElementsUsing(FromToCurrentTriple)
+ .containsExactly(
+ // Initial transition A to B. This transition will never be consumed by anyone given
+ // that it has the same (from, to) pair as the next transition.
+ Triple(SceneA, SceneB, SceneB),
+
+ // Initial transition reversed, B back to A.
+ Triple(SceneA, SceneB, SceneA),
+
+ // A to C.
+ Triple(SceneA, SceneC, SceneC),
+ )
+ .inOrder()
+ }
+
+ @Test
+ fun animateToFromScene() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, transitions {})
+
+ // Fake a transition from A to B that has a non 0 velocity.
+ val progressVelocity = 1f
+ val aToB =
+ transition(
+ from = SceneA,
+ to = SceneB,
+ current = { SceneB },
+ // Progress must be > visibility threshold otherwise we will directly snap to A.
+ progress = { 0.5f },
+ progressVelocity = { progressVelocity },
+ onFinish = { launch {} },
+ )
+ state.startTransition(aToB, transitionKey = null)
+
+ // Animate back to A. The previous transition is reversed, i.e. it has the same (from, to)
+ // pair, and its velocity is used when animating the progress back to 0.
+ val bToA = checkNotNull(state.setTargetScene(SceneA, coroutineScope = this))
+ testScheduler.runCurrent()
+ assertThat(bToA).hasFromScene(SceneA)
+ assertThat(bToA).hasToScene(SceneB)
+ assertThat(bToA).hasCurrentScene(SceneA)
+ assertThat(bToA).hasProgressVelocity(progressVelocity)
+ }
+
+ @Test
+ fun animateToToScene() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, transitions {})
+
+ // Fake a transition from A to B with current scene = A that has a non 0 velocity.
+ val progressVelocity = -1f
+ val aToB =
+ transition(
+ from = SceneA,
+ to = SceneB,
+ current = { SceneA },
+ progressVelocity = { progressVelocity },
+ onFinish = { launch {} },
+ )
+ state.startTransition(aToB, transitionKey = null)
+
+ // Animate to B. The previous transition is reversed, i.e. it has the same (from, to) pair,
+ // and its velocity is used when animating the progress to 1.
+ val bToA = checkNotNull(state.setTargetScene(SceneB, coroutineScope = this))
+ testScheduler.runCurrent()
+ assertThat(bToA).hasFromScene(SceneA)
+ assertThat(bToA).hasToScene(SceneB)
+ assertThat(bToA).hasCurrentScene(SceneB)
+ assertThat(bToA).hasProgressVelocity(progressVelocity)
+ }
+
+ companion object {
+ val FromToCurrentTriple =
+ Correspondence.transforming(
+ { transition: TransitionState.Transition? ->
+ Triple(transition?.fromScene, transition?.toScene, transition?.currentScene)
+ },
+ "(from, to, current) triple"
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index 224ffe29a1b8..9523896e5c00 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -43,6 +43,7 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.subjects.assertThat
import com.android.compose.test.assertSizeIsEqualTo
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
@@ -157,8 +158,8 @@ class MovableElementTest {
fromSceneZIndex: Float,
toSceneZIndex: Float
): SceneKey {
- assertThat(transition.fromScene).isEqualTo(TestScenes.SceneA)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
+ assertThat(transition).hasFromScene(TestScenes.SceneA)
+ assertThat(transition).hasToScene(TestScenes.SceneB)
assertThat(fromSceneZIndex).isEqualTo(0)
assertThat(toSceneZIndex).isEqualTo(1)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 93e94f8f95a2..d2c8bd6928ee 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -25,6 +25,7 @@ import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
import com.android.compose.animation.scene.TestScenes.SceneD
+import com.android.compose.animation.scene.subjects.assertThat
import com.android.compose.animation.scene.transition.link.StateLink
import com.android.compose.test.runMonotonicClockTest
import com.google.common.truth.Truth.assertThat
@@ -322,8 +323,8 @@ class SceneTransitionLayoutStateTest {
// Go back to A.
state.setTargetScene(SceneA, coroutineScope = this)
testScheduler.advanceUntilIdle()
- assertThat(state.currentTransition).isNull()
- assertThat(state.transitionState.currentScene).isEqualTo(SceneA)
+ assertThat(state.transitionState).isIdle()
+ assertThat(state.transitionState).hasCurrentScene(SceneA)
// Specific transition from A to B.
assertThat(
@@ -477,23 +478,24 @@ class SceneTransitionLayoutStateTest {
overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) }
}
)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasNoOverscrollSpec()
// overscroll for SceneA is NOT defined
progress.value = -0.1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
// scroll from SceneA to SceneB
progress.value = 0.5f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
progress.value = 1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
// overscroll for SceneB is defined
progress.value = 1.1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
- assertThat(state.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneB)
+ val overscrollSpec = assertThat(transition).hasOverscrollSpec()
+ assertThat(overscrollSpec.scene).isEqualTo(SceneB)
}
@Test
@@ -507,23 +509,25 @@ class SceneTransitionLayoutStateTest {
overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) }
}
)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasNoOverscrollSpec()
// overscroll for SceneA is defined
progress.value = -0.1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
- assertThat(state.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneA)
+ val overscrollSpec = assertThat(transition).hasOverscrollSpec()
+ assertThat(overscrollSpec.scene).isEqualTo(SceneA)
// scroll from SceneA to SceneB
progress.value = 0.5f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
progress.value = 1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
// overscroll for SceneB is NOT defined
progress.value = 1.1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
}
@Test
@@ -534,22 +538,24 @@ class SceneTransitionLayoutStateTest {
progress = { progress.value },
sceneTransitions = transitions {}
)
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasNoOverscrollSpec()
// overscroll for SceneA is NOT defined
progress.value = -0.1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
// scroll from SceneA to SceneB
progress.value = 0.5f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
progress.value = 1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
// overscroll for SceneB is NOT defined
progress.value = 1.1f
- assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ assertThat(transition).hasNoOverscrollSpec()
}
@Test
@@ -629,4 +635,19 @@ class SceneTransitionLayoutStateTest {
Log.setWtfHandler(originalHandler)
}
}
+
+ @Test
+ fun snapToScene() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutState(SceneA)
+
+ // Transition to B.
+ state.setTargetScene(SceneB, coroutineScope = this)
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasCurrentScene(SceneB)
+
+ // Snap to C.
+ state.snapToScene(SceneC)
+ assertThat(state.transitionState).isIdle()
+ assertThat(state.transitionState).hasCurrentScene(SceneC)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 7836581c86e8..692c18bb8ac5 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -51,6 +51,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
+import com.android.compose.animation.scene.subjects.assertThat
import com.android.compose.test.assertSizeIsEqualTo
import com.android.compose.test.subjects.DpOffsetSubject
import com.android.compose.test.subjects.assertThat
@@ -147,34 +148,34 @@ class SceneTransitionLayoutTest {
rule.onNodeWithText("SceneA").assertIsDisplayed()
rule.onNodeWithText("SceneB").assertDoesNotExist()
rule.onNodeWithText("SceneC").assertDoesNotExist()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// Change to scene B. Only that scene is displayed.
currentScene = SceneB
rule.onNodeWithText("SceneA").assertDoesNotExist()
rule.onNodeWithText("SceneB").assertIsDisplayed()
rule.onNodeWithText("SceneC").assertDoesNotExist()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneB)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
}
@Test
fun testBack() {
rule.setContent { TestContent() }
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneA)
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
rule.activity.onBackPressed()
rule.waitForIdle()
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneB)
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
}
@Test
fun testTransitionState() {
rule.setContent { TestContent() }
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// We will advance the clock manually.
rule.mainClock.autoAdvance = false
@@ -182,45 +183,38 @@ class SceneTransitionLayoutTest {
// Change the current scene. Until composition is triggered, this won't change the layout
// state.
currentScene = SceneB
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// On the next frame, we will recompose because currentScene changed, which will start the
// transition (i.e. it will change the transitionState to be a Transition) in a
// LaunchedEffect.
rule.mainClock.advanceTimeByFrame()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Transition::class.java)
- val transition = layoutState.transitionState as TransitionState.Transition
- assertThat(transition.fromScene).isEqualTo(SceneA)
- assertThat(transition.toScene).isEqualTo(SceneB)
- assertThat(transition.progress).isEqualTo(0f)
+ val transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(SceneB)
+ assertThat(transition).hasProgress(0f)
// Then, on the next frame, the animator we started gets its initial value and clock
// starting time. We are now at progress = 0f.
rule.mainClock.advanceTimeByFrame()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((layoutState.transitionState as TransitionState.Transition).progress)
- .isEqualTo(0f)
+ assertThat(transition).hasProgress(0f)
// The test transition lasts 480ms. 240ms after the start of the transition, we are at
// progress = 0.5f.
rule.mainClock.advanceTimeBy(TestTransitionDuration / 2)
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((layoutState.transitionState as TransitionState.Transition).progress)
- .isEqualTo(0.5f)
+ assertThat(transition).hasProgress(0.5f)
// (240-16) ms later, i.e. one frame before the transition is finished, we are at
// progress=(480-16)/480.
rule.mainClock.advanceTimeBy(TestTransitionDuration / 2 - 16)
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((layoutState.transitionState as TransitionState.Transition).progress)
- .isEqualTo((TestTransitionDuration - 16) / 480f)
+ assertThat(transition).hasProgress((TestTransitionDuration - 16) / 480f)
// one frame (16ms) later, the transition is finished and we are in the idle state in scene
// B.
rule.mainClock.advanceTimeByFrame()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneB)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
}
@Test
@@ -261,8 +255,8 @@ class SceneTransitionLayoutTest {
// 100.dp. We pause at the middle of the transition, so it should now be 75.dp given that we
// use a linear interpolator. Foo was at (x = layoutSize - 50dp, y = 0) in SceneA and is
// going to (x = 0, y = 0), so the offset should now be half what it was.
- assertThat((layoutState.transitionState as TransitionState.Transition).progress)
- .isEqualTo(0.5f)
+ var transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasProgress(0.5f)
sharedFoo.assertWidthIsEqualTo(75.dp)
sharedFoo.assertHeightIsEqualTo(75.dp)
sharedFoo.assertPositionInRootIsEqualTo(
@@ -290,8 +284,8 @@ class SceneTransitionLayoutTest {
val expectedSize = 100.dp + (150.dp - 100.dp) * interpolatedProgress
sharedFoo = rule.onNode(isElement(TestElements.Foo, SceneC))
- assertThat((layoutState.transitionState as TransitionState.Transition).progress)
- .isEqualTo(interpolatedProgress)
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasProgress(interpolatedProgress)
sharedFoo.assertWidthIsEqualTo(expectedSize)
sharedFoo.assertHeightIsEqualTo(expectedSize)
sharedFoo.assertPositionInRootIsEqualTo(expectedLeft, expectedTop)
@@ -305,16 +299,16 @@ class SceneTransitionLayoutTest {
// Wait for the transition to C to finish.
rule.mainClock.advanceTimeBy(TestTransitionDuration)
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
// Go back to scene A. This should happen instantly (once the animation started, i.e. after
// 2 frames) given that we use a snap() animation spec.
currentScene = SceneA
rule.mainClock.advanceTimeByFrame()
rule.mainClock.advanceTimeByFrame()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
}
@Test
@@ -384,7 +378,9 @@ class SceneTransitionLayoutTest {
rule.mainClock.advanceTimeByFrame()
rule.mainClock.advanceTimeBy(duration / 2)
rule.waitForIdle()
- assertThat(state.currentTransition?.progress).isEqualTo(0.5f)
+
+ var transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasProgress(0.5f)
// A and B are composed.
rule.onNodeWithTag("aRoot").assertExists()
@@ -396,7 +392,9 @@ class SceneTransitionLayoutTest {
rule.mainClock.advanceTimeByFrame()
rule.mainClock.advanceTimeByFrame()
rule.waitForIdle()
- assertThat(state.currentTransition?.progress).isEqualTo(0f)
+
+ transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasProgress(0f)
// A, B and C are composed.
rule.onNodeWithTag("aRoot").assertExists()
@@ -405,7 +403,7 @@ class SceneTransitionLayoutTest {
// Let A => B finish.
rule.mainClock.advanceTimeBy(duration / 2L)
- assertThat(state.currentTransition?.progress).isEqualTo(0.5f)
+ assertThat(transition).hasProgress(0.5f)
rule.waitForIdle()
// B and C are composed.
@@ -416,8 +414,8 @@ class SceneTransitionLayoutTest {
// Let B => C finish.
rule.mainClock.advanceTimeBy(duration / 2L)
rule.mainClock.advanceTimeByFrame()
- assertThat(state.currentTransition).isNull()
rule.waitForIdle()
+ assertThat(state.transitionState).isIdle()
// Only C is composed.
rule.onNodeWithTag("aRoot").assertDoesNotExist()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index f034c184b794..1dd9322b3ad5 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -38,6 +38,9 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestScenes.SceneA
+import com.android.compose.animation.scene.TestScenes.SceneB
+import com.android.compose.animation.scene.subjects.assertThat
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
@@ -65,7 +68,7 @@ class SwipeToSceneTest {
@get:Rule val rule = createComposeRule()
private fun layoutState(
- initialScene: SceneKey = TestScenes.SceneA,
+ initialScene: SceneKey = SceneA,
transitions: SceneTransitions = EmptyTestTransitions,
) = MutableSceneTransitionLayoutState(initialScene, transitions)
@@ -80,22 +83,21 @@ class SwipeToSceneTest {
modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.debugName),
) {
scene(
- TestScenes.SceneA,
+ SceneA,
userActions =
if (swipesEnabled())
mapOf(
- Swipe.Left to TestScenes.SceneB,
+ Swipe.Left to SceneB,
Swipe.Down to TestScenes.SceneC,
- Swipe.Up to TestScenes.SceneB,
+ Swipe.Up to SceneB,
)
else emptyMap(),
) {
Box(Modifier.fillMaxSize())
}
scene(
- TestScenes.SceneB,
- userActions =
- if (swipesEnabled()) mapOf(Swipe.Right to TestScenes.SceneA) else emptyMap(),
+ SceneB,
+ userActions = if (swipesEnabled()) mapOf(Swipe.Right to SceneA) else emptyMap(),
) {
Box(Modifier.fillMaxSize())
}
@@ -104,11 +106,10 @@ class SwipeToSceneTest {
userActions =
if (swipesEnabled())
mapOf(
- Swipe.Down to TestScenes.SceneA,
- Swipe(SwipeDirection.Down, pointerCount = 2) to TestScenes.SceneB,
- Swipe(SwipeDirection.Right, fromSource = Edge.Left) to
- TestScenes.SceneB,
- Swipe(SwipeDirection.Down, fromSource = Edge.Top) to TestScenes.SceneB,
+ Swipe.Down to SceneA,
+ Swipe(SwipeDirection.Down, pointerCount = 2) to SceneB,
+ Swipe(SwipeDirection.Right, fromSource = Edge.Left) to SceneB,
+ Swipe(SwipeDirection.Down, fromSource = Edge.Top) to SceneB,
)
else emptyMap(),
) {
@@ -129,8 +130,8 @@ class SwipeToSceneTest {
TestContent(layoutState)
}
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// Drag left (i.e. from right to left) by 55dp. We pick 55dp here because 56dp is the
// positional threshold from which we commit the gesture.
@@ -144,31 +145,27 @@ class SwipeToSceneTest {
// We should be at a progress = 55dp / LayoutWidth given that we use the layout size in
// the gesture axis as swipe distance.
- var transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneA)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
- assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
- assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
- assertThat(transition.isInitiatedByUserInput).isTrue()
+ var transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(SceneB)
+ assertThat(transition).hasCurrentScene(SceneA)
+ assertThat(transition).hasProgress(55.dp / LayoutWidth)
+ assertThat(transition).isInitiatedByUserInput()
// Release the finger. We should now be animating back to A (currentScene = SceneA) given
// that 55dp < positional threshold.
rule.onRoot().performTouchInput { up() }
- transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneA)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
- assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
- assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
- assertThat(transition.isInitiatedByUserInput).isTrue()
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(SceneB)
+ assertThat(transition).hasCurrentScene(SceneA)
+ assertThat(transition).hasProgress(55.dp / LayoutWidth)
+ assertThat(transition).isInitiatedByUserInput()
// Wait for the animation to finish. We should now be in scene A.
rule.waitForIdle()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// Now we do the same but vertically and with a drag distance of 56dp, which is >=
// positional threshold.
@@ -178,31 +175,27 @@ class SwipeToSceneTest {
}
// Drag is in progress, so currentScene = SceneA and progress = 56dp / LayoutHeight
- transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneA)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
- assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
- assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
- assertThat(transition.isInitiatedByUserInput).isTrue()
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(TestScenes.SceneC)
+ assertThat(transition).hasCurrentScene(SceneA)
+ assertThat(transition).hasProgress(56.dp / LayoutHeight)
+ assertThat(transition).isInitiatedByUserInput()
// Release the finger. We should now be animating to C (currentScene = SceneC) given
// that 56dp >= positional threshold.
rule.onRoot().performTouchInput { up() }
- transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneA)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
- assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC)
- assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
- assertThat(transition.isInitiatedByUserInput).isTrue()
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(TestScenes.SceneC)
+ assertThat(transition).hasCurrentScene(TestScenes.SceneC)
+ assertThat(transition).hasProgress(56.dp / LayoutHeight)
+ assertThat(transition).isInitiatedByUserInput()
// Wait for the animation to finish. We should now be in scene C.
rule.waitForIdle()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
}
@Test
@@ -216,8 +209,8 @@ class SwipeToSceneTest {
TestContent(layoutState)
}
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// Swipe left (i.e. from right to left) using a velocity of 124 dp/s. We pick 124 dp/s here
// because 125 dp/s is the velocity threshold from which we commit the gesture. We also use
@@ -233,18 +226,16 @@ class SwipeToSceneTest {
// We should be animating back to A (currentScene = SceneA) given that 124 dp/s < velocity
// threshold.
- var transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneA)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
- assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
- assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
+ var transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(SceneB)
+ assertThat(transition).hasCurrentScene(SceneA)
+ assertThat(transition).hasProgress(55.dp / LayoutWidth)
// Wait for the animation to finish. We should now be in scene A.
rule.waitForIdle()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// Now we do the same but vertically and with a swipe velocity of 126dp, which is >
// velocity threshold. Note that in theory we could have used 125 dp (= velocity threshold)
@@ -259,18 +250,16 @@ class SwipeToSceneTest {
}
// We should be animating to C (currentScene = SceneC).
- transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneA)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
- assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC)
- assertThat(transition.progress).isEqualTo(55.dp / LayoutHeight)
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(TestScenes.SceneC)
+ assertThat(transition).hasCurrentScene(TestScenes.SceneC)
+ assertThat(transition).hasProgress(55.dp / LayoutHeight)
// Wait for the animation to finish. We should now be in scene C.
rule.waitForIdle()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
}
@Test
@@ -286,8 +275,8 @@ class SwipeToSceneTest {
TestContent(layoutState)
}
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
// Swipe down with two fingers.
rule.onRoot().performTouchInput {
@@ -298,18 +287,16 @@ class SwipeToSceneTest {
}
// We are transitioning to B because we used 2 fingers.
- val transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneC)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
+ val transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(TestScenes.SceneC)
+ assertThat(transition).hasToScene(SceneB)
// Release the fingers and wait for the animation to end. We are back to C because we only
// swiped 10dp.
rule.onRoot().performTouchInput { repeat(2) { i -> up(pointerId = i) } }
rule.waitForIdle()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
}
@Test
@@ -325,8 +312,8 @@ class SwipeToSceneTest {
TestContent(layoutState)
}
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
// Swipe down from the top edge.
rule.onRoot().performTouchInput {
@@ -335,18 +322,16 @@ class SwipeToSceneTest {
}
// We are transitioning to B (and not A) because we started from the top edge.
- var transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneC)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
+ var transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(TestScenes.SceneC)
+ assertThat(transition).hasToScene(SceneB)
// Release the fingers and wait for the animation to end. We are back to C because we only
// swiped 10dp.
rule.onRoot().performTouchInput { up() }
rule.waitForIdle()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
// Swipe right from the left edge.
rule.onRoot().performTouchInput {
@@ -355,18 +340,16 @@ class SwipeToSceneTest {
}
// We are transitioning to B (and not A) because we started from the left edge.
- transition = layoutState.transitionState
- assertThat(transition).isInstanceOf(TransitionState.Transition::class.java)
- assertThat((transition as TransitionState.Transition).fromScene)
- .isEqualTo(TestScenes.SceneC)
- assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(TestScenes.SceneC)
+ assertThat(transition).hasToScene(SceneB)
// Release the fingers and wait for the animation to end. We are back to C because we only
// swiped 10dp.
rule.onRoot().performTouchInput { up() }
rule.waitForIdle()
- assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(TestScenes.SceneC)
}
@Test
@@ -380,7 +363,7 @@ class SwipeToSceneTest {
layoutState(
transitions =
transitions {
- from(TestScenes.SceneA, to = TestScenes.SceneB) {
+ from(SceneA, to = SceneB) {
distance = FixedDistance(verticalSwipeDistance)
}
}
@@ -395,12 +378,12 @@ class SwipeToSceneTest {
modifier = Modifier.size(LayoutWidth, LayoutHeight)
) {
scene(
- TestScenes.SceneA,
- userActions = mapOf(Swipe.Down to TestScenes.SceneB),
+ SceneA,
+ userActions = mapOf(Swipe.Down to SceneB),
) {
Spacer(Modifier.fillMaxSize())
}
- scene(TestScenes.SceneB) { Spacer(Modifier.fillMaxSize()) }
+ scene(SceneB) { Spacer(Modifier.fillMaxSize()) }
}
}
@@ -413,9 +396,9 @@ class SwipeToSceneTest {
}
// We should be at 50%
- val transition = layoutState.currentTransition
+ val transition = assertThat(layoutState.transitionState).isTransition()
assertThat(transition).isNotNull()
- assertThat(transition!!.progress).isEqualTo(0.5f)
+ assertThat(transition).hasProgress(0.5f)
}
@Test
@@ -434,15 +417,14 @@ class SwipeToSceneTest {
}
// We should still correctly compute that we are swiping down to scene C.
- var transition = layoutState.currentTransition
- assertThat(transition).isNotNull()
- assertThat(transition?.toScene).isEqualTo(TestScenes.SceneC)
+ var transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasToScene(TestScenes.SceneC)
// Release the finger, animating back to scene A.
rule.onRoot().performTouchInput { up() }
rule.waitForIdle()
- assertThat(layoutState.currentTransition).isNull()
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// Swipe up by exactly touchSlop, so that the drag overSlop is 0f.
rule.onRoot().performTouchInput {
@@ -451,15 +433,14 @@ class SwipeToSceneTest {
}
// We should still correctly compute that we are swiping up to scene B.
- transition = layoutState.currentTransition
- assertThat(transition).isNotNull()
- assertThat(transition?.toScene).isEqualTo(TestScenes.SceneB)
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasToScene(SceneB)
// Release the finger, animating back to scene A.
rule.onRoot().performTouchInput { up() }
rule.waitForIdle()
- assertThat(layoutState.currentTransition).isNull()
- assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
// Swipe left by exactly touchSlop, so that the drag overSlop is 0f.
rule.onRoot().performTouchInput {
@@ -468,14 +449,13 @@ class SwipeToSceneTest {
}
// We should still correctly compute that we are swiping down to scene B.
- transition = layoutState.currentTransition
- assertThat(transition).isNotNull()
- assertThat(transition?.toScene).isEqualTo(TestScenes.SceneB)
+ transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasToScene(SceneB)
}
@Test
fun swipeEnabledLater() {
- val layoutState = MutableSceneTransitionLayoutState(TestScenes.SceneA)
+ val layoutState = MutableSceneTransitionLayoutState(SceneA)
var swipesEnabled by mutableStateOf(false)
var touchSlop = 0f
rule.setContent {
@@ -509,34 +489,32 @@ class SwipeToSceneTest {
fun transitionKey() {
val transitionkey = TransitionKey(debugName = "foo")
val state =
- MutableSceneTransitionLayoutState(
- TestScenes.SceneA,
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
transitions {
- from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) }
- from(TestScenes.SceneA, to = TestScenes.SceneB, key = transitionkey) {
+ from(SceneA, to = SceneB) { fade(TestElements.Foo) }
+ from(SceneA, to = SceneB, key = transitionkey) {
fade(TestElements.Foo)
fade(TestElements.Bar)
}
}
)
- as MutableSceneTransitionLayoutStateImpl
var touchSlop = 0f
rule.setContent {
touchSlop = LocalViewConfiguration.current.touchSlop
SceneTransitionLayout(state, Modifier.size(LayoutWidth, LayoutHeight)) {
scene(
- TestScenes.SceneA,
+ SceneA,
userActions =
mapOf(
- Swipe.Down to TestScenes.SceneB,
- Swipe.Up to
- UserActionResult(TestScenes.SceneB, transitionKey = transitionkey)
+ Swipe.Down to SceneB,
+ Swipe.Up to UserActionResult(SceneB, transitionKey = transitionkey)
)
) {
Box(Modifier.fillMaxSize())
}
- scene(TestScenes.SceneB) { Box(Modifier.fillMaxSize()) }
+ scene(SceneB) { Box(Modifier.fillMaxSize()) }
}
}
@@ -546,12 +524,12 @@ class SwipeToSceneTest {
moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
}
- assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
+ assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
// Move the pointer up to swipe to scene B using the new transition.
rule.onRoot().performTouchInput { moveBy(Offset(0f, -1.dp.toPx()), delayMillis = 1_000) }
- assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
+ assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
}
@@ -567,19 +545,17 @@ class SwipeToSceneTest {
// the difference between the bottom of the scene and the bottom of the element,
// so that we use the offset and size of the element as well as the size of the
// scene.
- val fooSize = TestElements.Foo.targetSize(TestScenes.SceneB) ?: return 0f
- val fooOffset = TestElements.Foo.targetOffset(TestScenes.SceneB) ?: return 0f
- val sceneSize = TestScenes.SceneB.targetSize() ?: return 0f
+ val fooSize = TestElements.Foo.targetSize(SceneB) ?: return 0f
+ val fooOffset = TestElements.Foo.targetOffset(SceneB) ?: return 0f
+ val sceneSize = SceneB.targetSize() ?: return 0f
return sceneSize.height - fooOffset.y - fooSize.height
}
}
val state =
MutableSceneTransitionLayoutState(
- TestScenes.SceneA,
- transitions {
- from(TestScenes.SceneA, to = TestScenes.SceneB) { distance = swipeDistance }
- }
+ SceneA,
+ transitions { from(SceneA, to = SceneB) { distance = swipeDistance } }
)
val layoutSize = 200.dp
@@ -591,10 +567,10 @@ class SwipeToSceneTest {
touchSlop = LocalViewConfiguration.current.touchSlop
SceneTransitionLayout(state, Modifier.size(layoutSize)) {
- scene(TestScenes.SceneA, userActions = mapOf(Swipe.Up to TestScenes.SceneB)) {
+ scene(SceneA, userActions = mapOf(Swipe.Up to SceneB)) {
Box(Modifier.fillMaxSize())
}
- scene(TestScenes.SceneB) {
+ scene(SceneB) {
Box(Modifier.fillMaxSize()) {
Box(Modifier.offset(y = fooYOffset).element(TestElements.Foo).size(fooSize))
}
@@ -611,7 +587,9 @@ class SwipeToSceneTest {
}
rule.waitForIdle()
- assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
- assertThat(state.currentTransition!!.progress).isWithin(0.01f).of(0.5f)
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(SceneB)
+ assertThat(transition).hasProgress(0.5f, tolerance = 0.01f)
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
index c49a5b85ebe3..a609be48a225 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
@@ -29,6 +29,7 @@ fun transition(
to: SceneKey,
current: () -> SceneKey = { from },
progress: () -> Float = { 0f },
+ progressVelocity: () -> Float = { 0f },
interruptionProgress: () -> Float = { 100f },
isInitiatedByUserInput: Boolean = false,
isUserInputOngoing: Boolean = false,
@@ -42,6 +43,8 @@ fun transition(
get() = current()
override val progress: Float
get() = progress()
+ override val progressVelocity: Float
+ get() = progressVelocity()
override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput
override val isUserInputOngoing: Boolean = isUserInputOngoing
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
new file mode 100644
index 000000000000..348989218ce9
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.subjects
+
+import com.android.compose.animation.scene.OverscrollSpec
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionState
+import com.google.common.truth.Fact.simpleFact
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+import com.google.common.truth.Truth
+
+/** Assert on a [TransitionState]. */
+fun assertThat(state: TransitionState): TransitionStateSubject {
+ return Truth.assertAbout(TransitionStateSubject.transitionStates()).that(state)
+}
+
+/** Assert on a [TransitionState.Transition]. */
+fun assertThat(transitions: TransitionState.Transition): TransitionSubject {
+ return Truth.assertAbout(TransitionSubject.transitions()).that(transitions)
+}
+
+class TransitionStateSubject
+private constructor(
+ metadata: FailureMetadata,
+ private val actual: TransitionState,
+) : Subject(metadata, actual) {
+ fun hasCurrentScene(sceneKey: SceneKey) {
+ check("currentScene").that(actual.currentScene).isEqualTo(sceneKey)
+ }
+
+ fun isIdle(): TransitionState.Idle {
+ if (actual !is TransitionState.Idle) {
+ failWithActual(simpleFact("expected to be TransitionState.Idle"))
+ }
+
+ return actual as TransitionState.Idle
+ }
+
+ fun isTransition(): TransitionState.Transition {
+ if (actual !is TransitionState.Transition) {
+ failWithActual(simpleFact("expected to be TransitionState.Transition"))
+ }
+
+ return actual as TransitionState.Transition
+ }
+
+ companion object {
+ fun transitionStates() = Factory { metadata, actual: TransitionState ->
+ TransitionStateSubject(metadata, actual)
+ }
+ }
+}
+
+class TransitionSubject
+private constructor(
+ metadata: FailureMetadata,
+ private val actual: TransitionState.Transition,
+) : Subject(metadata, actual) {
+ fun hasCurrentScene(sceneKey: SceneKey) {
+ check("currentScene").that(actual.currentScene).isEqualTo(sceneKey)
+ }
+
+ fun hasFromScene(sceneKey: SceneKey) {
+ check("fromScene").that(actual.fromScene).isEqualTo(sceneKey)
+ }
+
+ fun hasToScene(sceneKey: SceneKey) {
+ check("toScene").that(actual.toScene).isEqualTo(sceneKey)
+ }
+
+ fun hasProgress(progress: Float, tolerance: Float = 0f) {
+ check("progress").that(actual.progress).isWithin(tolerance).of(progress)
+ }
+
+ fun hasProgressVelocity(progressVelocity: Float, tolerance: Float = 0f) {
+ check("progressVelocity")
+ .that(actual.progressVelocity)
+ .isWithin(tolerance)
+ .of(progressVelocity)
+ }
+
+ fun isInitiatedByUserInput() {
+ check("isInitiatedByUserInput").that(actual.isInitiatedByUserInput).isTrue()
+ }
+
+ fun hasIsUserInputOngoing(isUserInputOngoing: Boolean) {
+ check("isUserInputOngoing").that(actual.isUserInputOngoing).isEqualTo(isUserInputOngoing)
+ }
+
+ fun hasOverscrollSpec(): OverscrollSpec {
+ check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNotNull()
+ return actual.currentOverscrollSpec!!
+ }
+
+ fun hasNoOverscrollSpec() {
+ check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNull()
+ }
+
+ fun hasBouncingScene(scene: SceneKey) {
+ if (actual !is TransitionState.HasOverscrollProperties) {
+ failWithActual(simpleFact("expected to be TransitionState.HasOverscrollProperties"))
+ }
+
+ check("bouncingScene")
+ .that((actual as TransitionState.HasOverscrollProperties).bouncingScene)
+ .isEqualTo(scene)
+ }
+
+ companion object {
+ fun transitions() = Factory { metadata, actual: TransitionState.Transition ->
+ TransitionSubject(metadata, actual)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 447c28067200..6c3f3c181d45 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -17,8 +17,11 @@
package com.android.keyguard
+import android.app.admin.DevicePolicyManager
+import android.app.admin.flags.Flags as DevicePolicyFlags
import android.content.res.Configuration
import android.media.AudioManager
+import android.platform.test.annotations.EnableFlags
import android.telephony.TelephonyManager
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableResources
@@ -148,6 +151,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
@Mock private lateinit var faceAuthAccessibilityDelegate: FaceAuthAccessibilityDelegate
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var postureController: DevicePostureController
+ @Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Captor
private lateinit var swipeListenerArgumentCaptor:
@@ -273,6 +277,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
mSelectedUserInteractor,
deviceProvisionedController,
faceAuthAccessibilityDelegate,
+ devicePolicyManager,
keyguardTransitionInteractor,
{ primaryBouncerInteractor },
) {
@@ -934,6 +939,45 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
verify(viewFlipperController).asynchronouslyInflateView(any(), any(), any())
}
+ @Test
+ @EnableFlags(DevicePolicyFlags.FLAG_HEADLESS_SINGLE_USER_FIXES)
+ fun showAlmostAtWipeDialog_calledOnMainUser_setsCorrectUserType() {
+ val mainUserId = 10
+
+ underTest.showMessageForFailedUnlockAttempt(
+ /* userId = */ mainUserId,
+ /* expiringUserId = */ mainUserId,
+ /* mainUserId = */ mainUserId,
+ /* remainingBeforeWipe = */ 1,
+ /* failedAttempts = */ 1
+ )
+
+ verify(view)
+ .showAlmostAtWipeDialog(any(), any(), eq(KeyguardSecurityContainer.USER_TYPE_PRIMARY))
+ }
+
+ @Test
+ @EnableFlags(DevicePolicyFlags.FLAG_HEADLESS_SINGLE_USER_FIXES)
+ fun showAlmostAtWipeDialog_calledOnNonMainUser_setsCorrectUserType() {
+ val secondaryUserId = 10
+ val mainUserId = 0
+
+ underTest.showMessageForFailedUnlockAttempt(
+ /* userId = */ secondaryUserId,
+ /* expiringUserId = */ secondaryUserId,
+ /* mainUserId = */ mainUserId,
+ /* remainingBeforeWipe = */ 1,
+ /* failedAttempts = */ 1
+ )
+
+ verify(view)
+ .showAlmostAtWipeDialog(
+ any(),
+ any(),
+ eq(KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER)
+ )
+ }
+
private val registeredSwipeListener: KeyguardSecurityContainer.SwipeListener
get() {
underTest.onViewAttached()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryImplTest.kt
new file mode 100644
index 000000000000..c0d481c6e659
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryImplTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@android.platform.test.annotations.EnabledOnRavenwood
+class OneHandedModeRepositoryImplTest : SysuiTestCase() {
+
+ private val testUser1 = UserHandle.of(1)!!
+ private val testUser2 = UserHandle.of(2)!!
+ private val testDispatcher = StandardTestDispatcher()
+ private val scope = TestScope(testDispatcher)
+ private val settings: FakeSettings = FakeSettings()
+
+ private val underTest: OneHandedModeRepository =
+ OneHandedModeRepositoryImpl(
+ testDispatcher,
+ scope.backgroundScope,
+ settings,
+ )
+
+ @Test
+ fun isEnabled_settingNotInitialized_returnsFalseByDefault() =
+ scope.runTest {
+ val actualValue by collectLastValue(underTest.isEnabled(testUser1))
+
+ runCurrent()
+
+ assertThat(actualValue).isFalse()
+ }
+
+ @Test
+ fun isEnabled_initiallyGetsSettingsValue() =
+ scope.runTest {
+ val actualValue by collectLastValue(underTest.isEnabled(testUser1))
+
+ settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier)
+ runCurrent()
+
+ assertThat(actualValue).isTrue()
+ }
+
+ @Test
+ fun isEnabled_settingUpdated_valueUpdated() =
+ scope.runTest {
+ val actualValue by collectLastValue(underTest.isEnabled(testUser1))
+ runCurrent()
+ assertThat(actualValue).isFalse()
+
+ settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier)
+ runCurrent()
+
+ assertThat(actualValue).isTrue()
+ runCurrent()
+
+ settings.putIntForUser(SETTING_NAME, DISABLED, testUser1.identifier)
+ runCurrent()
+ assertThat(actualValue).isFalse()
+ }
+
+ @Test
+ fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() =
+ scope.runTest {
+ val lastValueUser1 by collectLastValue(underTest.isEnabled(testUser1))
+ val lastValueUser2 by collectLastValue(underTest.isEnabled(testUser2))
+
+ settings.putIntForUser(SETTING_NAME, DISABLED, testUser1.identifier)
+ settings.putIntForUser(SETTING_NAME, DISABLED, testUser2.identifier)
+ runCurrent()
+ assertThat(lastValueUser1).isFalse()
+ assertThat(lastValueUser2).isFalse()
+
+ settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier)
+ runCurrent()
+ assertThat(lastValueUser1).isTrue()
+ assertThat(lastValueUser2).isFalse()
+ }
+
+ @Test
+ fun setEnabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(true, testUser1)
+ runCurrent()
+ assertThat(success).isTrue()
+
+ val actualValue = settings.getIntForUser(SETTING_NAME, testUser1.identifier)
+ assertThat(actualValue).isEqualTo(ENABLED)
+ }
+
+ @Test
+ fun setDisabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(false, testUser1)
+ runCurrent()
+ assertThat(success).isTrue()
+
+ val actualValue = settings.getIntForUser(SETTING_NAME, testUser1.identifier)
+ assertThat(actualValue).isEqualTo(DISABLED)
+ }
+
+ companion object {
+ private const val SETTING_NAME = Settings.Secure.ONE_HANDED_MODE_ENABLED
+ private const val DISABLED = 0
+ private const val ENABLED = 1
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index 81878aaf4a18..0c5e726e17aa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -17,6 +17,8 @@
package com.android.systemui.authentication.domain.interactor
import android.app.admin.DevicePolicyManager
+import android.app.admin.flags.Flags as DevicePolicyFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
@@ -32,6 +34,8 @@ import com.android.systemui.authentication.shared.model.AuthenticationWipeModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -410,12 +414,16 @@ class AuthenticationInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(DevicePolicyFlags.FLAG_HEADLESS_SINGLE_USER_FIXES)
fun upcomingWipe() =
testScope.runTest {
val upcomingWipe by collectLastValue(underTest.upcomingWipe)
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
val correctPin = FakeAuthenticationRepository.DEFAULT_PIN
val wrongPin = FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 }
+ kosmos.fakeUserRepository.asMainUser()
+ kosmos.fakeAuthenticationRepository.profileWithMinFailedUnlockAttemptsForWipe =
+ FakeUserRepository.MAIN_USER_ID
underTest.authenticate(correctPin)
assertThat(upcomingWipe).isNull()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 20beabb983da..2546f27cb351 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.coroutines.FlowValue
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
@@ -144,6 +145,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private val testScope = kosmos.testScope
private val fakeUserRepository = kosmos.fakeUserRepository
+ private val fakeExecutor = kosmos.fakeExecutor
private lateinit var authStatus: FlowValue<FaceAuthenticationStatus?>
private lateinit var detectStatus: FlowValue<FaceDetectionStatus?>
private lateinit var authRunning: FlowValue<Boolean?>
@@ -220,12 +222,12 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
testScope.backgroundScope,
testDispatcher,
testDispatcher,
+ fakeExecutor,
sessionTracker,
uiEventLogger,
FaceAuthenticationLogger(logcatLogBuffer("DeviceEntryFaceAuthRepositoryLog")),
biometricSettingsRepository,
deviceEntryFingerprintAuthRepository,
- trustRepository,
keyguardRepository,
powerInteractor,
keyguardInteractor,
@@ -292,6 +294,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
fun faceLockoutStatusIsPropagated() =
testScope.runTest {
initCollectors()
+ fakeExecutor.runAllReady()
verify(faceManager).addLockoutResetCallback(faceLockoutResetCallback.capture())
allPreconditionsToRunFaceAuthAreTrue()
@@ -1177,6 +1180,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
private suspend fun TestScope.allPreconditionsToRunFaceAuthAreTrue() {
+ fakeExecutor.runAllReady()
verify(faceManager, atLeastOnce())
.addLockoutResetCallback(faceLockoutResetCallback.capture())
trustRepository.setCurrentUserTrusted(false)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 412292554e73..bf0939c6c46f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -235,7 +235,13 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
.isEqualTo(
listOf(
// The initial transition will also get sent when collect started
- TransitionStep(OFF, LOCKSCREEN, 0f, STARTED),
+ TransitionStep(
+ OFF,
+ LOCKSCREEN,
+ 0f,
+ STARTED,
+ ownerName = "KeyguardTransitionRepository(boot)"
+ ),
steps[0],
steps[3],
steps[6]
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
index 31b67b43adc4..f52c66e24907 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
@@ -16,36 +16,57 @@
package com.android.systemui.keyguard.ui.viewmodel
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
-import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@ExperimentalCoroutinesApi
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class AodToLockscreenTransitionViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class AodToLockscreenTransitionViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
val kosmos = testKosmos()
val testScope = kosmos.testScope
val repository = kosmos.fakeKeyguardTransitionRepository
- val shadeRepository = kosmos.fakeShadeRepository
+ val shadeTestUtil by lazy { kosmos.shadeTestUtil }
val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
- val underTest = kosmos.aodToLockscreenTransitionViewModel
+ lateinit var underTest: AodToLockscreenTransitionViewModel
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
+ @Before
+ fun setup() {
+ underTest = kosmos.aodToLockscreenTransitionViewModel
+ }
@Test
fun deviceEntryParentViewShows() =
@@ -65,7 +86,7 @@ class AodToLockscreenTransitionViewModelTest : SysuiTestCase() {
testScope.runTest {
val alpha by collectLastValue(underTest.notificationAlpha)
- shadeRepository.setQsExpansion(0.5f)
+ shadeTestUtil.setQsExpansion(0.5f)
runCurrent()
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
@@ -81,7 +102,7 @@ class AodToLockscreenTransitionViewModelTest : SysuiTestCase() {
testScope.runTest {
val alpha by collectLastValue(underTest.notificationAlpha)
- shadeRepository.setQsExpansion(0f)
+ shadeTestUtil.setQsExpansion(0f)
runCurrent()
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
index bef951554b50..e3ae3ba4cedd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
@@ -16,13 +16,14 @@
package com.android.systemui.keyguard.ui.viewmodel
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -32,31 +33,53 @@ import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
-import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@ExperimentalCoroutinesApi
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class LockscreenToAodTransitionViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class LockscreenToAodTransitionViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
fakeFeatureFlagsClassic.apply { set(FULL_SCREEN_USER_SWITCHER, false) }
}
private val testScope = kosmos.testScope
private val repository = kosmos.fakeKeyguardTransitionRepository
- private val shadeRepository = kosmos.shadeRepository
private val keyguardRepository = kosmos.fakeKeyguardRepository
private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
private val biometricSettingsRepository = kosmos.biometricSettingsRepository
- private val underTest = kosmos.lockscreenToAodTransitionViewModel
+
+ private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
+
+ lateinit var underTest: LockscreenToAodTransitionViewModel
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
+ @Before
+ fun setup() {
+ underTest = kosmos.lockscreenToAodTransitionViewModel
+ }
@Test
fun backgroundViewAlpha_shadeNotExpanded() =
@@ -195,11 +218,11 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() {
private fun shadeExpanded(expanded: Boolean) {
if (expanded) {
- shadeRepository.setQsExpansion(1f)
+ shadeTestUtil.setQsExpansion(1f)
} else {
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
- shadeRepository.setQsExpansion(0f)
- shadeRepository.setLockscreenShadeExpansion(0f)
+ shadeTestUtil.setQsExpansion(0f)
+ shadeTestUtil.setLockscreenShadeExpansion(0f)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index 8f04ec3814eb..adeb395fc142 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -18,24 +18,25 @@
package com.android.systemui.keyguard.ui.viewmodel
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
-import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
-import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.ShadeTestUtil
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
@@ -45,10 +46,12 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class LockscreenToDreamingTransitionViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
@@ -56,14 +59,27 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
}
private val testScope = kosmos.testScope
private lateinit var repository: FakeKeyguardTransitionRepository
- private lateinit var shadeRepository: ShadeRepository
+ private lateinit var shadeTestUtil: ShadeTestUtil
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var underTest: LockscreenToDreamingTransitionViewModel
+ // add to init block
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
@Before
fun setUp() {
repository = kosmos.fakeKeyguardTransitionRepository
- shadeRepository = kosmos.shadeRepository
+ shadeTestUtil = kosmos.shadeTestUtil
keyguardRepository = kosmos.fakeKeyguardRepository
underTest = kosmos.lockscreenToDreamingTransitionViewModel
}
@@ -177,11 +193,11 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
private fun shadeExpanded(expanded: Boolean) {
if (expanded) {
- shadeRepository.setQsExpansion(1f)
+ shadeTestUtil.setQsExpansion(1f)
} else {
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
- shadeRepository.setQsExpansion(0f)
- shadeRepository.setLockscreenShadeExpansion(0f)
+ shadeTestUtil.setQsExpansion(0f)
+ shadeTestUtil.setLockscreenShadeExpansion(0f)
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index b120f8776d9d..f8da74fdd742 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -18,27 +18,28 @@
package com.android.systemui.keyguard.ui.viewmodel
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
-import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.ShadeTestUtil
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
@@ -48,25 +49,40 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class LockscreenToOccludedTransitionViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
}
private val testScope = kosmos.testScope
private lateinit var repository: FakeKeyguardTransitionRepository
- private lateinit var shadeRepository: ShadeRepository
+ private lateinit var shadeTestUtil: ShadeTestUtil
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var configurationRepository: FakeConfigurationRepository
private lateinit var underTest: LockscreenToOccludedTransitionViewModel
+ // add to init block
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
@Before
fun setUp() {
repository = kosmos.fakeKeyguardTransitionRepository
- shadeRepository = kosmos.shadeRepository
+ shadeTestUtil = kosmos.shadeTestUtil
keyguardRepository = kosmos.fakeKeyguardRepository
configurationRepository = kosmos.fakeConfigurationRepository
underTest = kosmos.lockscreenToOccludedTransitionViewModel
@@ -200,11 +216,11 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
private fun shadeExpanded(expanded: Boolean) {
if (expanded) {
- shadeRepository.setQsExpansion(1f)
+ shadeTestUtil.setQsExpansion(1f)
} else {
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
- shadeRepository.setQsExpansion(0f)
- shadeRepository.setLockscreenShadeExpansion(0f)
+ shadeTestUtil.setQsExpansion(0f)
+ shadeTestUtil.setLockscreenShadeExpansion(0f)
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
index 43ab93a18118..d5df159d6d1e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
@@ -16,11 +16,12 @@
package com.android.systemui.keyguard.ui.viewmodel
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -29,29 +30,50 @@ import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
-import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth
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 platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@ExperimentalCoroutinesApi
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class LockscreenToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameterization?) :
+ SysuiTestCase() {
private val kosmos =
testKosmos().apply {
fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
}
private val testScope = kosmos.testScope
private val repository = kosmos.fakeKeyguardTransitionRepository
- private val shadeRepository = kosmos.shadeRepository
+ private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
private val keyguardRepository = kosmos.fakeKeyguardRepository
- private val underTest = kosmos.lockscreenToPrimaryBouncerTransitionViewModel
+ private lateinit var underTest: LockscreenToPrimaryBouncerTransitionViewModel
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
+ @Before
+ fun setup() {
+ underTest = kosmos.lockscreenToPrimaryBouncerTransitionViewModel
+ }
@Test
fun deviceEntryParentViewAlpha_shadeExpanded() =
@@ -119,11 +141,11 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
private fun shadeExpanded(expanded: Boolean) {
if (expanded) {
- shadeRepository.setQsExpansion(1f)
+ shadeTestUtil.setQsExpansion(1f)
} else {
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
- shadeRepository.setQsExpansion(0f)
- shadeRepository.setLockscreenShadeExpansion(0f)
+ shadeTestUtil.setQsExpansion(0f)
+ shadeTestUtil.setLockscreenShadeExpansion(0f)
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt
index abc684c09f49..5661bd388757 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.shade.ui.viewmodel
+package com.android.systemui.notifications.ui.viewmodel
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -32,6 +32,7 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ui.viewmodel.notificationsShadeSceneViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileDataInteractorTest.kt
new file mode 100644
index 000000000000..0761ee734830
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileDataInteractorTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded.domain.interactor
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.oneHandedModeRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.onehanded.domain.OneHandedModeTileDataInteractor
+import com.android.wm.shell.onehanded.OneHanded
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class OneHandedModeTileDataInteractorTest : SysuiTestCase() {
+
+ private val kosmos = Kosmos()
+ private val testUser = UserHandle.of(1)!!
+ private val oneHandedModeRepository = kosmos.oneHandedModeRepository
+ private val underTest: OneHandedModeTileDataInteractor =
+ OneHandedModeTileDataInteractor(oneHandedModeRepository)
+
+ @Test
+ fun availability_matchesController() = runTest {
+ val expectedAvailability = OneHanded.sIsSupportOneHandedMode
+ val availability by collectLastValue(underTest.availability(testUser))
+
+ assertThat(availability).isEqualTo(expectedAvailability)
+ }
+
+ @Test
+ fun data_matchesRepository() = runTest {
+ val lastData by
+ collectLastValue(underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)))
+ runCurrent()
+ assertThat(lastData!!.isEnabled).isFalse()
+
+ oneHandedModeRepository.setIsEnabled(true, testUser)
+ runCurrent()
+ assertThat(lastData!!.isEnabled).isTrue()
+
+ oneHandedModeRepository.setIsEnabled(false, testUser)
+ runCurrent()
+ assertThat(lastData!!.isEnabled).isFalse()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileUserActionInteractorTest.kt
new file mode 100644
index 000000000000..3f17d4cec643
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/domain/interactor/OneHandedModeTileUserActionInteractorTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded.domain.interactor
+
+import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeOneHandedModeRepository
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.onehanded.domain.OneHandedModeTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@EnabledOnRavenwood
+@RunWith(AndroidJUnit4::class)
+class OneHandedModeTileUserActionInteractorTest : SysuiTestCase() {
+
+ private val testUser = UserHandle.of(1)
+ private val repository = FakeOneHandedModeRepository()
+ private val inputHandler = FakeQSTileIntentUserInputHandler()
+
+ private val underTest =
+ OneHandedModeTileUserActionInteractor(
+ repository,
+ inputHandler,
+ )
+
+ @Test
+ fun handleClickWhenEnabled() = runTest {
+ val wasEnabled = true
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(
+ QSTileInputTestKtx.click(OneHandedModeTileModel(wasEnabled), testUser)
+ )
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleClickWhenDisabled() = runTest {
+ val wasEnabled = false
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(
+ QSTileInputTestKtx.click(OneHandedModeTileModel(wasEnabled), testUser)
+ )
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleLongClickWhenDisabled() = runTest {
+ val enabled = false
+
+ underTest.handleInput(
+ QSTileInputTestKtx.longClick(OneHandedModeTileModel(enabled), testUser)
+ )
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_ONE_HANDED_SETTINGS)
+ }
+ }
+
+ @Test
+ fun handleLongClickWhenEnabled() = runTest {
+ val enabled = true
+
+ underTest.handleInput(
+ QSTileInputTestKtx.longClick(OneHandedModeTileModel(enabled), testUser)
+ )
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_ONE_HANDED_SETTINGS)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt
new file mode 100644
index 000000000000..7ef020da8b67
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded.ui
+
+import android.graphics.drawable.TestStubDrawable
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tileimpl.SubtitleArrayMapping
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
+import com.android.systemui.qs.tiles.impl.onehanded.qsOneHandedModeTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class OneHandedModeTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val config = kosmos.qsOneHandedModeTileConfig
+ private val subtitleArrayId = SubtitleArrayMapping.getSubtitleId(config.tileSpec.spec)
+ private val subtitleArray by lazy { context.resources.getStringArray(subtitleArrayId) }
+
+ private lateinit var mapper: OneHandedModeTileMapper
+
+ @Before
+ fun setup() {
+ mapper =
+ OneHandedModeTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(
+ com.android.internal.R.drawable.ic_qs_one_handed_mode,
+ TestStubDrawable()
+ )
+ }
+ .resources,
+ context.theme
+ )
+ }
+
+ @Test
+ fun disabledModel() {
+ val inputModel = OneHandedModeTileModel(false)
+
+ val outputState = mapper.map(config, inputModel)
+
+ val expectedState =
+ createOneHandedModeTileState(
+ QSTileState.ActivationState.INACTIVE,
+ subtitleArray[1],
+ com.android.internal.R.drawable.ic_qs_one_handed_mode
+ )
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun enabledModel() {
+ val inputModel = OneHandedModeTileModel(true)
+
+ val outputState = mapper.map(config, inputModel)
+
+ val expectedState =
+ createOneHandedModeTileState(
+ QSTileState.ActivationState.ACTIVE,
+ subtitleArray[2],
+ com.android.internal.R.drawable.ic_qs_one_handed_mode
+ )
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ private fun createOneHandedModeTileState(
+ activationState: QSTileState.ActivationState,
+ secondaryLabel: String,
+ iconRes: Int,
+ ): QSTileState {
+ val label = context.getString(R.string.quick_settings_onehanded_label)
+ return QSTileState(
+ { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
+ label,
+ activationState,
+ secondaryLabel,
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
+ label,
+ null,
+ QSTileState.SideViewIcon.None,
+ QSTileState.EnabledState.ENABLED,
+ Switch::class.qualifiedName
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt
new file mode 100644
index 000000000000..034c2e9b6789
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.viewmodel
+
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Swipe
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ui.viewmodel.quickSettingsShadeSceneViewModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+@EnableSceneContainer
+class QuickSettingsShadeSceneViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val sceneInteractor = kosmos.sceneInteractor
+ private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
+
+ private val underTest = kosmos.quickSettingsShadeSceneViewModel
+
+ @Test
+ fun upTransitionSceneKey_deviceLocked_lockscreen() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ lockDevice()
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun upTransitionSceneKey_deviceUnlocked_gone() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ lockDevice()
+ unlockDevice()
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
+ fun upTransitionSceneKey_authMethodSwipe_lockscreenNotDismissed_goesToLockscreen() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.None
+ )
+ sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun upTransitionSceneKey_authMethodSwipe_lockscreenDismissed_goesToGone() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.None
+ )
+ runCurrent()
+ sceneInteractor.changeScene(Scenes.Gone, "reason")
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone)
+ }
+
+ private fun TestScope.lockDevice() {
+ val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus)
+
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ assertThat(deviceUnlockStatus?.isUnlocked).isFalse()
+ sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+ runCurrent()
+ }
+
+ private fun TestScope.unlockDevice() {
+ val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus)
+
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ assertThat(deviceUnlockStatus?.isUnlocked).isTrue()
+ sceneInteractor.changeScene(Scenes.Gone, "reason")
+ runCurrent()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 883760c67310..df30c4bf1b5a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -70,6 +70,9 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
underTest.changeScene(Scenes.Shade)
assertThat(currentScene).isEqualTo(Scenes.Shade)
+
+ underTest.snapToScene(Scenes.QuickSettings)
+ assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
}
@Test(expected = IllegalStateException::class)
@@ -79,6 +82,13 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
underTest.changeScene(Scenes.Shade)
}
+ @Test(expected = IllegalStateException::class)
+ fun snapToScene_noSuchSceneInContainer_throws() {
+ kosmos.sceneKeys = listOf(Scenes.QuickSettings, Scenes.Lockscreen)
+ val underTest = kosmos.sceneContainerRepository
+ underTest.snapToScene(Scenes.Shade)
+ }
+
@Test
fun isVisible() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index c16d5224e0ba..2fa94effdbd4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -126,6 +126,71 @@ class SceneInteractorTest : SysuiTestCase() {
}
@Test
+ fun snapToScene_toUnknownScene_doesNothing() =
+ testScope.runTest {
+ val sceneKeys =
+ listOf(
+ Scenes.QuickSettings,
+ Scenes.Shade,
+ Scenes.Lockscreen,
+ Scenes.Gone,
+ Scenes.Communal,
+ )
+ val navigationDistances =
+ mapOf(
+ Scenes.Gone to 0,
+ Scenes.Lockscreen to 0,
+ Scenes.Communal to 1,
+ Scenes.Shade to 2,
+ Scenes.QuickSettings to 3,
+ )
+ kosmos.sceneContainerConfig =
+ SceneContainerConfig(sceneKeys, Scenes.Lockscreen, navigationDistances)
+ underTest = kosmos.sceneInteractor
+ val currentScene by collectLastValue(underTest.currentScene)
+ val previousScene = currentScene
+ assertThat(previousScene).isNotEqualTo(Scenes.Bouncer)
+ underTest.snapToScene(Scenes.Bouncer, "reason")
+ assertThat(currentScene).isEqualTo(previousScene)
+ }
+
+ @Test
+ fun snapToScene() =
+ testScope.runTest {
+ underTest = kosmos.sceneInteractor
+
+ val currentScene by collectLastValue(underTest.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+ underTest.snapToScene(Scenes.Shade, "reason")
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ }
+
+ @Test
+ fun snapToScene_toGoneWhenUnl_doesNotThrow() =
+ testScope.runTest {
+ underTest = kosmos.sceneInteractor
+
+ val currentScene by collectLastValue(underTest.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
+
+ underTest.snapToScene(Scenes.Gone, "reason")
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun snapToScene_toGoneWhenStillLocked_throws() =
+ testScope.runTest {
+ underTest = kosmos.sceneInteractor
+ underTest.snapToScene(Scenes.Gone, "reason")
+ }
+
+ @Test
fun sceneChanged_inDataSource() =
testScope.runTest {
underTest = kosmos.sceneInteractor
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
new file mode 100644
index 000000000000..35e4047109d5
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.notifications.ui.composable.NotificationScrimNestedScrollConnection
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationScrimNestedScrollConnectionTest : SysuiTestCase() {
+ private var isStarted = false
+ private var scrimOffset = 0f
+ private var contentHeight = 0f
+ private var isCurrentGestureOverscroll = false
+
+ private val scrollConnection =
+ NotificationScrimNestedScrollConnection(
+ scrimOffset = { scrimOffset },
+ snapScrimOffset = { _ -> },
+ animateScrimOffset = { _ -> },
+ minScrimOffset = { MIN_SCRIM_OFFSET },
+ maxScrimOffset = MAX_SCRIM_OFFSET,
+ contentHeight = { contentHeight },
+ minVisibleScrimHeight = { MIN_VISIBLE_SCRIM_HEIGHT },
+ isCurrentGestureOverscroll = { isCurrentGestureOverscroll },
+ onStart = { isStarted = true },
+ onStop = { isStarted = false },
+ )
+
+ @Test
+ fun onScrollUp_canStartPreScroll_contentNotExpanded_ignoreScroll() = runTest {
+ contentHeight = COLLAPSED_CONTENT_HEIGHT
+
+ val offsetConsumed =
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = -1f),
+ source = NestedScrollSource.Drag,
+ )
+
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+ assertThat(isStarted).isEqualTo(false)
+ }
+
+ @Test
+ fun onScrollUp_canStartPreScroll_contentExpandedAtMinOffset_ignoreScroll() = runTest {
+ contentHeight = EXPANDED_CONTENT_HEIGHT
+ scrimOffset = MIN_SCRIM_OFFSET
+
+ val offsetConsumed =
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = -1f),
+ source = NestedScrollSource.Drag,
+ )
+
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+ assertThat(isStarted).isEqualTo(false)
+ }
+
+ @Test
+ fun onScrollUp_canStartPreScroll_contentExpanded_consumeScroll() = runTest {
+ contentHeight = EXPANDED_CONTENT_HEIGHT
+
+ val availableOffset = Offset(x = 0f, y = -1f)
+ val offsetConsumed =
+ scrollConnection.onPreScroll(
+ available = availableOffset,
+ source = NestedScrollSource.Drag,
+ )
+
+ assertThat(offsetConsumed).isEqualTo(availableOffset)
+ assertThat(isStarted).isEqualTo(true)
+ }
+
+ @Test
+ fun onScrollUp_canStartPreScroll_contentExpanded_consumeScrollWithRemainder() = runTest {
+ contentHeight = EXPANDED_CONTENT_HEIGHT
+ scrimOffset = MIN_SCRIM_OFFSET + 1
+
+ val availableOffset = Offset(x = 0f, y = -2f)
+ val consumableOffset = Offset(x = 0f, y = -1f)
+ val offsetConsumed =
+ scrollConnection.onPreScroll(
+ available = availableOffset,
+ source = NestedScrollSource.Drag,
+ )
+
+ assertThat(offsetConsumed).isEqualTo(consumableOffset)
+ assertThat(isStarted).isEqualTo(true)
+ }
+
+ @Test
+ fun onScrollUp_canStartPostScroll_ignoreScroll() = runTest {
+ val offsetConsumed =
+ scrollConnection.onPostScroll(
+ consumed = Offset.Zero,
+ available = Offset(x = 0f, y = -1f),
+ source = NestedScrollSource.Drag,
+ )
+
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+ assertThat(isStarted).isEqualTo(false)
+ }
+
+ @Test
+ fun onScrollDown_canStartPreScroll_ignoreScroll() = runTest {
+ val offsetConsumed =
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = 1f),
+ source = NestedScrollSource.Drag,
+ )
+
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+ assertThat(isStarted).isEqualTo(false)
+ }
+
+ @Test
+ fun onScrollDown_canStartPostScroll_consumeScroll() = runTest {
+ scrimOffset = MIN_SCRIM_OFFSET
+
+ val availableOffset = Offset(x = 0f, y = 1f)
+ val offsetConsumed =
+ scrollConnection.onPostScroll(
+ consumed = Offset.Zero,
+ available = availableOffset,
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(offsetConsumed).isEqualTo(availableOffset)
+ assertThat(isStarted).isEqualTo(true)
+ }
+
+ @Test
+ fun onScrollDown_canStartPostScroll_consumeScrollWithRemainder() = runTest {
+ scrimOffset = MAX_SCRIM_OFFSET - 1
+
+ val availableOffset = Offset(x = 0f, y = 2f)
+ val consumableOffset = Offset(x = 0f, y = 1f)
+ val offsetConsumed =
+ scrollConnection.onPostScroll(
+ consumed = Offset.Zero,
+ available = availableOffset,
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(offsetConsumed).isEqualTo(consumableOffset)
+ assertThat(isStarted).isEqualTo(true)
+ }
+
+ @Test
+ fun canStartPostScroll_atMaxOffset_ignoreScroll() = runTest {
+ scrimOffset = MAX_SCRIM_OFFSET
+
+ val offsetConsumed =
+ scrollConnection.onPostScroll(
+ consumed = Offset.Zero,
+ available = Offset(x = 0f, y = 1f),
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+ assertThat(isStarted).isEqualTo(false)
+ }
+
+ @Test
+ fun canStartPostScroll_externalOverscrollGesture_startButIgnoreScroll() = runTest {
+ scrimOffset = MAX_SCRIM_OFFSET
+ isCurrentGestureOverscroll = true
+
+ val offsetConsumed =
+ scrollConnection.onPostScroll(
+ consumed = Offset.Zero,
+ available = Offset(x = 0f, y = 1f),
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+ assertThat(isStarted).isEqualTo(true)
+ }
+
+ @Test
+ fun canContinueScroll_inBetweenMinMaxOffset_true() = runTest {
+ scrimOffset = (MIN_SCRIM_OFFSET + MAX_SCRIM_OFFSET) / 2f
+ contentHeight = EXPANDED_CONTENT_HEIGHT
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = -1f),
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(isStarted).isEqualTo(true)
+
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = 1f),
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(isStarted).isEqualTo(true)
+ }
+
+ @Test
+ fun canContinueScroll_atMaxOffset_false() = runTest {
+ scrimOffset = MAX_SCRIM_OFFSET
+ contentHeight = EXPANDED_CONTENT_HEIGHT
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = -1f),
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(isStarted).isEqualTo(true)
+
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = 1f),
+ source = NestedScrollSource.Drag
+ )
+
+ assertThat(isStarted).isEqualTo(false)
+ }
+
+ companion object {
+ const val MIN_SCRIM_OFFSET = -100f
+ const val MAX_SCRIM_OFFSET = 0f
+
+ const val EXPANDED_CONTENT_HEIGHT = 200f
+ const val COLLAPSED_CONTENT_HEIGHT = 40f
+
+ const val MIN_VISIBLE_SCRIM_HEIGHT = 50f
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index 78b76151e7e6..cbbc4d897048 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,116 +18,92 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel
import android.graphics.Rect
import android.graphics.drawable.Icon
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.andSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.DarkIconDispatcher
-import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
-import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationIconViewStateRepository
-import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.headsUpNotificationIconViewStateRepository
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher
-import com.android.systemui.statusbar.phone.data.repository.FakeDarkIconRepository
-import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.statusbar.phone.data.repository.fakeDarkIconRepository
+import com.android.systemui.statusbar.phone.dozeParameters
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.ui.isAnimating
import com.android.systemui.util.ui.value
import com.google.common.truth.Truth.assertThat
-import dagger.BindsInstance
-import dagger.Component
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
-
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- BiometricsDomainLayerModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent : SysUITestComponent<NotificationIconContainerStatusBarViewModel> {
-
- val activeNotificationsRepository: ActiveNotificationListRepository
- val darkIconRepository: FakeDarkIconRepository
- val deviceProvisioningRepository: FakeDeviceProvisioningRepository
- val headsUpViewStateRepository: HeadsUpNotificationIconViewStateRepository
- val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- val keyguardRepository: FakeKeyguardRepository
- val powerRepository: FakePowerRepository
- val shadeRepository: FakeShadeRepository
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- mocks: TestMocksModule,
- featureFlags: FakeFeatureFlagsClassicModule,
- ): TestComponent
+@RunWith(ParameterizedAndroidJunit4::class)
+class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterization?) :
+ SysuiTestCase() {
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
}
}
- private val dozeParams: DozeParameters = mock()
-
- private val testComponent: TestComponent =
- DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
- },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParams,
- ),
- )
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val powerRepository = kosmos.fakePowerRepository
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val darkIconRepository = kosmos.fakeDarkIconRepository
+ private val headsUpViewStateRepository = kosmos.headsUpNotificationIconViewStateRepository
+ private val activeNotificationsRepository = kosmos.activeNotificationListRepository
+
+ private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
+
+ private val dozeParams = kosmos.dozeParameters
+
+ lateinit var underTest: NotificationIconContainerStatusBarViewModel
@Before
fun setup() {
- testComponent.apply {
- keyguardRepository.setKeyguardShowing(false)
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.AWAKE,
- lastWakeReason = WakeSleepReason.OTHER,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- }
+ underTest = kosmos.notificationIconContainerStatusBarViewModel
+ keyguardRepository.setKeyguardShowing(false)
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.OTHER,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
}
@Test
fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -150,7 +126,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -173,7 +149,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -194,7 +170,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
- testComponent.runTest {
+ testScope.runTest {
val animationsEnabled by collectLastValue(underTest.animationsEnabled)
assertThat(animationsEnabled).isTrue()
@@ -218,7 +194,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun animationsEnabled_isTrue_whenNotAsleep() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.AWAKE,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -236,7 +212,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() =
- testComponent.runTest {
+ testScope.runTest {
val animationsEnabled by collectLastValue(underTest.animationsEnabled)
keyguardTransitionRepository.sendTransitionStep(
@@ -257,7 +233,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun iconColors_testsDarkBounds() =
- testComponent.runTest {
+ testScope.runTest {
darkIconRepository.darkState.value =
SysuiDarkIconDispatcher.DarkChange(
emptyList(),
@@ -280,7 +256,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun iconColors_staticDrawableColor_notInDarkTintArea() =
- testComponent.runTest {
+ testScope.runTest {
darkIconRepository.darkState.value =
SysuiDarkIconDispatcher.DarkChange(
listOf(Rect(0, 0, 5, 5)),
@@ -295,7 +271,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun iconColors_notInDarkTintArea() =
- testComponent.runTest {
+ testScope.runTest {
darkIconRepository.darkState.value =
SysuiDarkIconDispatcher.DarkChange(
listOf(Rect(0, 0, 5, 5)),
@@ -309,9 +285,9 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun isolatedIcon_animateOnAppear_shadeCollapsed() =
- testComponent.runTest {
+ testScope.runTest {
val icon: Icon = mock()
- shadeRepository.setLegacyShadeExpansion(0f)
+ shadeTestUtil.setShadeExpansion(0f)
activeNotificationsRepository.activeNotifications.value =
ActiveNotificationsStore.Builder()
.apply {
@@ -336,9 +312,9 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun isolatedIcon_dontAnimateOnAppear_shadeExpanded() =
- testComponent.runTest {
+ testScope.runTest {
val icon: Icon = mock()
- shadeRepository.setLegacyShadeExpansion(.5f)
+ shadeTestUtil.setShadeExpansion(.5f)
activeNotificationsRepository.activeNotifications.value =
ActiveNotificationsStore.Builder()
.apply {
@@ -363,7 +339,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun isolatedIcon_updateWhenIconDataChanges() =
- testComponent.runTest {
+ testScope.runTest {
val icon: Icon = mock()
val isolatedIcon by collectLastValue(underTest.isolatedIcon)
runCurrent()
@@ -390,7 +366,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
@Test
fun isolatedIcon_lastMessageIsFromReply_notNull() =
- testComponent.runTest {
+ testScope.runTest {
val icon: Icon = mock()
headsUpViewStateRepository.isolatedNotification.value = "notif1"
activeNotificationsRepository.activeNotifications.value =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
index 327a07d6179f..327a07d6179f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 3408e06fe713..2cd295c6045d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -61,6 +61,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -654,7 +655,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization?) :
var notificationCount = 10
val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
-
+ advanceTimeBy(50L)
showLockscreen()
overrideResource(R.bool.config_use_split_notification_shade, false)
@@ -668,12 +669,14 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization?) :
// Also updates when directly requested (as it would from NotificationStackScrollLayout)
notificationCount = 25
sharedNotificationContainerInteractor.notificationStackChanged()
+ advanceTimeBy(50L)
assertThat(maxNotifications).isEqualTo(25)
// Also ensure another collection starts with the same value. As an example, folding
// then unfolding will restart the coroutine and it must get the last value immediately.
val newMaxNotifications by
collectLastValue(underTest.getMaxNotifications(calculateSpace))
+ advanceTimeBy(50L)
assertThat(newMaxNotifications).isEqualTo(25)
}
@@ -683,7 +686,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization?) :
var notificationCount = 10
val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
-
+ advanceTimeBy(50L)
showLockscreen()
overrideResource(R.bool.config_use_split_notification_shade, false)
@@ -718,6 +721,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization?) :
testScope.runTest {
val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> 10 }
val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
+ advanceTimeBy(50L)
// Show lockscreen with shade expanded
showLockscreenWithShadeExpanded()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt
index 03a39f8f07d8..2d8cd930d8fa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt
@@ -23,9 +23,9 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
-import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
-import com.android.systemui.util.kotlin.BooleanFlowOperators.or
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -45,21 +45,21 @@ class BooleanFlowOperatorsTest : SysuiTestCase() {
@Test
fun and_allTrue_returnsTrue() =
testScope.runTest {
- val result by collectLastValue(and(TRUE, TRUE))
+ val result by collectLastValue(allOf(TRUE, TRUE))
assertThat(result).isTrue()
}
@Test
fun and_anyFalse_returnsFalse() =
testScope.runTest {
- val result by collectLastValue(and(TRUE, FALSE, TRUE))
+ val result by collectLastValue(allOf(TRUE, FALSE, TRUE))
assertThat(result).isFalse()
}
@Test
fun and_allFalse_returnsFalse() =
testScope.runTest {
- val result by collectLastValue(and(FALSE, FALSE, FALSE))
+ val result by collectLastValue(allOf(FALSE, FALSE, FALSE))
assertThat(result).isFalse()
}
@@ -68,7 +68,7 @@ class BooleanFlowOperatorsTest : SysuiTestCase() {
testScope.runTest {
val flow1 = MutableStateFlow(false)
val flow2 = MutableStateFlow(false)
- val values by collectValues(and(flow1, flow2))
+ val values by collectValues(allOf(flow1, flow2))
assertThat(values).containsExactly(false)
flow1.value = true
@@ -81,21 +81,21 @@ class BooleanFlowOperatorsTest : SysuiTestCase() {
@Test
fun or_allTrue_returnsTrue() =
testScope.runTest {
- val result by collectLastValue(or(TRUE, TRUE))
+ val result by collectLastValue(anyOf(TRUE, TRUE))
assertThat(result).isTrue()
}
@Test
fun or_anyTrue_returnsTrue() =
testScope.runTest {
- val result by collectLastValue(or(FALSE, TRUE, FALSE))
+ val result by collectLastValue(anyOf(FALSE, TRUE, FALSE))
assertThat(result).isTrue()
}
@Test
fun or_allFalse_returnsFalse() =
testScope.runTest {
- val result by collectLastValue(or(FALSE, FALSE, FALSE))
+ val result by collectLastValue(anyOf(FALSE, FALSE, FALSE))
assertThat(result).isFalse()
}
@@ -104,7 +104,7 @@ class BooleanFlowOperatorsTest : SysuiTestCase() {
testScope.runTest {
val flow1 = MutableStateFlow(false)
val flow2 = MutableStateFlow(false)
- val values by collectValues(or(flow1, flow2))
+ val values by collectValues(anyOf(flow1, flow2))
assertThat(values).containsExactly(false)
flow1.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
index dc9613904e4e..dddf582908c7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
@@ -61,6 +61,7 @@ class AncSliceRepositoryTest : SysuiTestCase() {
AncSliceRepositoryImpl(
localMediaRepositoryFactory,
testScope.testScheduler,
+ testScope.testScheduler,
sliceViewManager,
)
}
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 427373de8bcc..b4198806c642 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -23,9 +23,9 @@
<string name="keyguard_enter_your_pin" msgid="5429932527814874032">"‏أدخل رقم التعريف الشخصي (PIN)"</string>
<string name="keyguard_enter_pin" msgid="8114529922480276834">"أدخِل رقم التعريف الشخصي"</string>
<string name="keyguard_enter_your_pattern" msgid="351503370332324745">"أدخل النقش"</string>
- <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ارسم النقش."</string>
+ <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ارسم النقش"</string>
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"أدخل كلمة المرور"</string>
- <string name="keyguard_enter_password" msgid="6483623792371009758">"أدخِل كلمة المرور."</string>
+ <string name="keyguard_enter_password" msgid="6483623792371009758">"أدخِل كلمة المرور"</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"بطاقة غير صالحة."</string>
<string name="keyguard_charged" msgid="5478247181205188995">"اكتمل الشحن"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن لاسلكيًا"</string>
@@ -57,11 +57,11 @@
<string name="kg_wrong_pin" msgid="4160978845968732624">"رقم تعريف شخصي خاطئ"</string>
<string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"لقد أدخلت رقم تعريف شخصي غير صحيح. يُرجى إعادة المحاولة."</string>
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"جرّب فتح القفل باستخدام بصمة الإصبع."</string>
- <string name="kg_fp_not_recognized" msgid="5183108260932029241">"لم يتم التعرّف على البصمة."</string>
+ <string name="kg_fp_not_recognized" msgid="5183108260932029241">"لم يتم التعرّف على البصمة"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"لم يتم التعرّف على الوجه."</string>
- <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"يُرجى إعادة المحاولة أو إدخال رقم التعريف الشخصي."</string>
- <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"يُرجى إعادة المحاولة أو إدخال كلمة المرور."</string>
- <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"يُرجى إعادة المحاولة أو رسم النقش."</string>
+ <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"يُرجى إعادة المحاولة أو إدخال رقم التعريف الشخصي"</string>
+ <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"يُرجى إعادة المحاولة أو إدخال كلمة المرور"</string>
+ <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"يُرجى إعادة المحاولة أو رسم النقش"</string>
<string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"‏يجب إدخال رقم PIN لأنّك أجريت محاولات كثيرة جدًا."</string>
<string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"يجب إدخال كلمة المرور لأنك أجريت محاولات كثيرة جدًا."</string>
<string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"يجب رسم النقش لأنّك أجريت محاولات كثيرة جدًا."</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index ee27e83c587d..74b1fd3e45ba 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -57,7 +57,7 @@
<string name="kg_wrong_pin" msgid="4160978845968732624">"Pogrešan PIN"</string>
<string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Pogrešan PIN. Probajte ponovo."</string>
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ili otključajte otiskom prsta"</string>
- <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Otisak prsta neprepoznat"</string>
+ <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Otisak prsta nije prepoznat"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Lice nije prepoznato"</string>
<string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Probajte ponovo ili unesite PIN"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Probajte ponovo ili unesite lozinku"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 188a76a12f9f..822e16eeb79e 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -23,7 +23,7 @@
<string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Saisissez votre code"</string>
<string name="keyguard_enter_pin" msgid="8114529922480276834">"Saisissez le code"</string>
<string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Tracez votre schéma"</string>
- <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Dessinez un schéma"</string>
+ <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Dessinez le schéma"</string>
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Saisissez votre mot de passe"</string>
<string name="keyguard_enter_password" msgid="6483623792371009758">"Saisissez le mot de passe"</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Carte non valide."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index e5cd788200a9..26a4dc5b8068 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -57,11 +57,11 @@
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorrecto"</string>
<string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN incorrecto. Téntao."</string>
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Tamén podes desbloquealo coa impresión dixital"</string>
- <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impr. dixital non recoñec."</string>
+ <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impresión dixital non recoñecida"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"A cara non se recoñeceu"</string>
<string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Téntao de novo ou pon o PIN"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Téntao de novo ou pon o contrasinal"</string>
- <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Téntao de novo ou debuxa o contrasinal"</string>
+ <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Téntao de novo ou debuxa o padrón"</string>
<string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Requírese o PIN tras realizar demasiados intentos"</string>
<string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Requírese o contrasinal tras demasiados intentos"</string>
<string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Requírese o padrón tras realizar demasiados intentos"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 2b019039a01f..d9055817a764 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -57,11 +57,11 @@
<string name="kg_wrong_pin" msgid="4160978845968732624">"गलत पिन"</string>
<string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"गलत पिन. दोबारा डालें."</string>
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"फ़िंगरप्रिंट से अनलॉक करें"</string>
- <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फ़िंगरप्रिंट गलत है"</string>
+ <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फ़िंगरप्रिंट की पहचान नहीं हो पाई"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"चेहरा नहीं पहचाना गया"</string>
<string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"फिर से कोशिश करें या पिन डालें"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"फिर से कोशिश करें या पासवर्ड डालें"</string>
- <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"फिर से कोशिश करें या पैटर्न ड्रा करें"</string>
+ <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"फिर से कोशिश करें या पैटर्न ड्रॉ करें"</string>
<string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"कई बार कोशिश की जा चुकी है, इसलिए पिन डालें"</string>
<string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"कई बार कोशिश की जा चुकी है, इसलिए पासवर्ड डालें"</string>
<string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"कई बार कोशिश की जा चुकी है, इसलिए पैटर्न ड्रा करें"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 3dd42431e0ba..2bfdef6ca182 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -57,7 +57,7 @@
<string name="kg_wrong_pin" msgid="4160978845968732624">"गलत PIN"</string>
<string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN मिलेन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"वा फिंगरप्रिन्ट प्रयोग गरी अनलक गर्नुहोस्"</string>
- <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फिंगरप्रिन्ट पहिचान गर्न सकिएन"</string>
+ <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फिंगरप्रिन्ट मिलेन"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"अनुहार पहिचान गर्न सकिएन"</string>
<string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"फेरि प्रयास गर्नुहोस् वा PIN हाल्नुहोस्"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"फेरि प्रयास गर्नुहोस् वा पासवर्ड हाल्नुहोस्"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index c3863a975797..a35c3e654b3f 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -59,7 +59,7 @@
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Of ontgrendel met vingerafdruk"</string>
<string name="kg_fp_not_recognized" msgid="5183108260932029241">"Vingerafdruk niet herkend"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Gezicht niet herkend"</string>
- <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Probeer het opnieuw of geef de pincode op"</string>
+ <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Probeer het opnieuw of voer de pincode in"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Probeer het opnieuw of geef het wachtwoord op"</string>
<string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Probeer het opnieuw of teken het patroon"</string>
<string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Na te veel pogingen is de pincode vereist"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index b29220476224..9a26f7d7b8e9 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -57,7 +57,7 @@
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
<string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN errado. Tente de novo."</string>
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ou desbloqueie com a impressão digital"</string>
- <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impr. dig. não reconhecida"</string>
+ <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impressão digital não reconhecida"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Rosto não reconhecido"</string>
<string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Tente novamente ou introduza o PIN"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Tente novamente ou introduza a palavra-passe"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 34c93116f180..339a82a100be 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -57,7 +57,7 @@
<string name="kg_wrong_pin" msgid="4160978845968732624">"Погрешан PIN"</string>
<string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Погрешан PIN. Пробајте поново."</string>
<string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Или откључајте отиском прста"</string>
- <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Отисак прста непрепознат"</string>
+ <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Отисак прста није препознат"</string>
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Лице није препознато"</string>
<string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Пробајте поново или унесите PIN"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Пробајте поново или унесите лозинку"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 7d74c9cb8224..196df2889944 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -23,7 +23,7 @@
<string name="keyguard_enter_your_pin" msgid="5429932527814874032">"输入您的 PIN 码"</string>
<string name="keyguard_enter_pin" msgid="8114529922480276834">"输入 PIN 码"</string>
<string name="keyguard_enter_your_pattern" msgid="351503370332324745">"绘制解锁图案"</string>
- <string name="keyguard_enter_pattern" msgid="7616595160901084119">"绘制图案"</string>
+ <string name="keyguard_enter_pattern" msgid="7616595160901084119">"绘制解锁图案"</string>
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"输入您的密码"</string>
<string name="keyguard_enter_password" msgid="6483623792371009758">"输入密码"</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM 卡无效。"</string>
@@ -61,7 +61,7 @@
<string name="bouncer_face_not_recognized" msgid="1666128054475597485">"无法识别面孔"</string>
<string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"请重试,或输入 PIN 码"</string>
<string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"请重试,或输入密码"</string>
- <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"请重试,或绘制图案"</string>
+ <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"请重试,或绘制解锁图案"</string>
<string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"如果出错的尝试次数太多,必须输入 PIN 码才能解锁"</string>
<string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"如果出错的尝试次数太多,必须输入密码才能解锁"</string>
<string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"如果出错的尝试次数太多,必须绘制图案才能解锁"</string>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index c43e394cb97a..da12dd731c23 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -36,7 +36,6 @@
</style>
<style name="Keyguard.Bouncer.SecondaryMessage" parent="Theme.SystemUI">
<item name="android:textSize">14sp</item>
- <item name="android:lineHeight">20dp</item>
<item name="android:maxLines">@integer/bouncer_secondary_message_lines</item>
<item name="android:lines">@integer/bouncer_secondary_message_lines</item>
<item name="android:textAlignment">center</item>
diff --git a/packages/SystemUI/res/drawable/shelf_action_chip_divider.xml b/packages/SystemUI/res/drawable/shelf_action_chip_divider.xml
index a5b44e564157..0a1f2a8f5048 100644
--- a/packages/SystemUI/res/drawable/shelf_action_chip_divider.xml
+++ b/packages/SystemUI/res/drawable/shelf_action_chip_divider.xml
@@ -16,6 +16,6 @@
<shape xmlns:android = "http://schemas.android.com/apk/res/android">
<size
- android:width = "@dimen/overlay_action_chip_margin_start"
+ android:width = "@dimen/shelf_action_chip_margin_start"
android:height = "0dp"/>
</shape>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay2.xml b/packages/SystemUI/res/layout/clipboard_overlay2.xml
new file mode 100644
index 000000000000..33ad2cd3a30f
--- /dev/null
+++ b/packages/SystemUI/res/layout/clipboard_overlay2.xml
@@ -0,0 +1,191 @@
+<?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");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.systemui.clipboardoverlay.ClipboardOverlayView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/clipboard_ui"
+ android:theme="@style/FloatingOverlay"
+ android:alpha="0"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/clipboard_overlay_window_name">
+ <FrameLayout
+ android:id="@+id/actions_container_background"
+ android:visibility="gone"
+ android:layout_height="0dp"
+ android:layout_width="0dp"
+ android:elevation="4dp"
+ android:background="@drawable/shelf_action_chip_container_background"
+ android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
+ android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/actions_container"
+ app:layout_constraintEnd_toEndOf="@+id/actions_container"
+ app:layout_constraintBottom_toBottomOf="parent"/>
+ <HorizontalScrollView
+ android:id="@+id/actions_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
+ android:paddingEnd="@dimen/overlay_action_container_padding_end"
+ android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
+ android:elevation="4dp"
+ android:scrollbars="none"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintWidth_percent="1.0"
+ app:layout_constraintWidth_max="wrap"
+ app:layout_constraintStart_toEndOf="@+id/preview_border"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background">
+ <LinearLayout
+ android:id="@+id/actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/shelf_action_chip_margin_start"
+ android:showDividers="middle"
+ android:divider="@drawable/shelf_action_chip_divider"
+ android:animateLayoutChanges="true">
+ <include layout="@layout/shelf_action_chip"
+ android:id="@+id/share_chip"/>
+ <include layout="@layout/shelf_action_chip"
+ android:id="@+id/remote_copy_chip"/>
+ </LinearLayout>
+ </HorizontalScrollView>
+ <View
+ android:id="@+id/preview_border"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginStart="@dimen/overlay_preview_container_margin"
+ android:layout_marginTop="@dimen/overlay_border_width_neg"
+ android:layout_marginEnd="@dimen/overlay_border_width_neg"
+ android:layout_marginBottom="@dimen/overlay_preview_container_margin"
+ android:elevation="7dp"
+ android:background="@drawable/overlay_border"
+ app:layout_constraintStart_toStartOf="@id/actions_container_background"
+ app:layout_constraintTop_toTopOf="@id/clipboard_preview"
+ app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background"/>
+ <FrameLayout
+ android:id="@+id/clipboard_preview"
+ android:layout_width="@dimen/clipboard_preview_size"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/overlay_border_width"
+ android:layout_marginBottom="@dimen/overlay_border_width"
+ android:layout_gravity="center"
+ android:elevation="7dp"
+ android:background="@drawable/overlay_preview_background"
+ android:clipChildren="true"
+ android:clipToOutline="true"
+ android:clipToPadding="true"
+ app:layout_constraintStart_toStartOf="@id/preview_border"
+ app:layout_constraintBottom_toBottomOf="@id/preview_border">
+ <TextView android:id="@+id/text_preview"
+ android:textFontWeight="500"
+ android:padding="8dp"
+ android:gravity="center|start"
+ android:ellipsize="end"
+ android:autoSizeTextType="uniform"
+ android:autoSizeMinTextSize="@dimen/clipboard_overlay_min_font"
+ android:autoSizeMaxTextSize="@dimen/clipboard_overlay_max_font"
+ android:textColor="?attr/overlayButtonTextColor"
+ android:textColorLink="?attr/overlayButtonTextColor"
+ android:background="?androidprv:attr/colorAccentSecondary"
+ android:layout_width="@dimen/clipboard_preview_size"
+ android:layout_height="@dimen/clipboard_preview_size"/>
+ <ImageView
+ android:id="@+id/image_preview"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true"
+ android:contentDescription="@string/clipboard_image_preview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/hidden_preview"
+ android:visibility="gone"
+ android:textFontWeight="500"
+ android:padding="8dp"
+ android:gravity="center"
+ android:textSize="14sp"
+ android:textColor="?attr/overlayButtonTextColor"
+ android:background="?androidprv:attr/colorAccentSecondary"
+ android:layout_width="@dimen/clipboard_preview_size"
+ android:layout_height="@dimen/clipboard_preview_size"/>
+ </FrameLayout>
+ <LinearLayout
+ android:id="@+id/minimized_preview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:elevation="7dp"
+ android:padding="8dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
+ android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
+ android:background="@drawable/clipboard_minimized_background">
+ <ImageView
+ android:src="@drawable/ic_content_paste"
+ android:tint="?attr/overlayButtonTextColor"
+ android:layout_width="24dp"
+ android:layout_height="24dp"/>
+ <ImageView
+ android:src="@*android:drawable/ic_chevron_end"
+ android:tint="?attr/overlayButtonTextColor"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:paddingEnd="-8dp"
+ android:paddingStart="-4dp"/>
+ </LinearLayout>
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/clipboard_content_top"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:barrierDirection="top"
+ app:constraint_referenced_ids="clipboard_preview,minimized_preview"/>
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/clipboard_content_end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ app:barrierDirection="end"
+ app:constraint_referenced_ids="clipboard_preview,minimized_preview"/>
+ <FrameLayout
+ android:id="@+id/dismiss_button"
+ android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
+ android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
+ android:elevation="10dp"
+ android:visibility="gone"
+ android:alpha="0"
+ app:layout_constraintStart_toEndOf="@id/clipboard_content_end"
+ app:layout_constraintEnd_toEndOf="@id/clipboard_content_end"
+ app:layout_constraintTop_toTopOf="@id/clipboard_content_top"
+ app:layout_constraintBottom_toTopOf="@id/clipboard_content_top"
+ android:contentDescription="@string/clipboard_dismiss_description">
+ <ImageView
+ android:id="@+id/dismiss_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/overlay_dismiss_button_margin"
+ android:background="@drawable/circular_background"
+ android:backgroundTint="?androidprv:attr/materialColorPrimaryFixedDim"
+ android:tint="?androidprv:attr/materialColorOnPrimaryFixed"
+ android:padding="4dp"
+ android:src="@drawable/ic_close"/>
+ </FrameLayout>
+</com.android.systemui.clipboardoverlay.ClipboardOverlayView> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 8a1f72658f12..ac523c17df25 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Gestoor in <xliff:g id="APP">%1$s</xliff:g> in die werkprofiel"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Gestoor in <xliff:g id="APP">%1$s</xliff:g> in die privaat profiel"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Lêers"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> het hierdie skermskoot bespeur."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> en ander oop apps het hierdie skermskoot bespeur."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Maak legstukke op sluitskerm toe"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Pasmaak legstukke"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Legstukke op sluitskerm"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"kies legstuk"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aftrekkieslys"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ontdemp %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> speel tans op"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Oudio sal speel op"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Bel met"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Stelsel-UI-ontvanger"</string>
<string name="status_bar" msgid="4357390266055077437">"Statusbalk"</string>
<string name="demo_mode" msgid="263484519766901593">"Stelsel-UI-demonstrasiemodus"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelliet, swak verbinding"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliet, goeie toestand"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding is beskikbaar"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliet-SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Werkprofiel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Pret vir party mense, maar nie vir almal nie"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Stelsel-UI-ontvanger gee jou ekstra maniere om die Android-gebruikerkoppelvlak in te stel en te pasmaak. Hierdie eksperimentele kenmerke kan in toekomstige uitreikings verander, breek of verdwyn. Gaan versigtig voort."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Voeg teël by"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Skuif na <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Voeg by posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisie is ongeldig."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Teël is bygevoeg"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Teël is verwyder"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e3bfff73e6a6..1236c976c57d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"<xliff:g id="APP">%1$s</xliff:g> ውስጥ የስራ መገለጫው ውስጥ ተቀምጧል"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"በግል መገለጫው ውስጥ በ<xliff:g id="APP">%1$s</xliff:g> ውስጥ ተቀምጧል"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ፋይሎች"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ይህን ቅጽበታዊ ገፅ ዕይታ ለይቷል።"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> እና ሌሎች ክፍት መተግበሪያዎች ይህን ቅጽበታዊ ገፅ ዕይታ ለይተዋል።"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ምግብሮችን በማያ ገጽ ቁልፍ ላይ ዝጋ"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ምግብሮችን አብጅ"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ምግብሮች በማያ ገጽ ቁልፍ ላይ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ምግብር ይምረጡ"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"የ%s ድምፀ-ከል አንሳ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> እየተጫወተ ያለው በ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ኦዲዮ ይጫወታል በ"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"በጥሪ ላይ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"የስርዓት በይነገጽ መቃኛ"</string>
<string name="status_bar" msgid="4357390266055077437">"የሁኔታ አሞሌ"</string>
<string name="demo_mode" msgid="263484519766901593">"የስርዓት ተጠቃሚ በይነገጽ ማሳያ ሁነታ"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ሳተላይት፣ ደካማ ግንኙነት"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ሳተላይት፣ ጥሩ ግንኙነት"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ሳተላይት፣ ግንኙነት አለ"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ሳተላይት ኤስኦኤስ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"የስራ መገለጫ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ለአንዳንዶች አስደሳች ቢሆንም ለሁሉም አይደለም"</string>
<string name="tuner_warning" msgid="1861736288458481650">"የስርዓት በይነገጽ መቃኛ የAndroid ተጠቃሚ በይነገጹን የሚነካኩበት እና የሚያበጁበት ተጨማሪ መንገዶች ይሰጠዎታል። እነዚህ የሙከራ ባህሪዎች ወደፊት በሚኖሩ ልቀቶች ላይ ሊለወጡ፣ ሊሰበሩ ወይም ሊጠፉ ይችላሉ። ከጥንቃቄ ጋር ወደፊት ይቀጥሉ።"</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ሰቅ ያክሉ"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ውሰድ"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ቦታ አክል"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"አቀማመጡ ተቀባይነት የለውም።"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"የ<xliff:g id="POSITION">%1$d</xliff:g> አቀማመጥ"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ሰቅ ታክሏል"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ሰቅ ተወግዷል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f49d60ee6bdc..2eed2aa5b04e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"تم حفظ لقطة الشاشة في \"<xliff:g id="APP">%1$s</xliff:g>\" في ملف العمل."</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"تم حفظ لقطة الشاشة في \"<xliff:g id="APP">%1$s</xliff:g>\" في الملف الشخصي الخاص."</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"الملفات"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"رصَد تطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\" لقطة الشاشة هذه."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"رصَد تطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\" والتطبيقات المفتوحة الأخرى لقطة الشاشة هذه."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"إغلاق التطبيقات المصغّرة على شاشة القفل"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"تخصيص التطبيقات المصغَّرة"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"التطبيقات المصغّرة على شاشة القفل"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"اختيار التطبيق المصغّر"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"القائمة المنسدلة"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"قمر صناعي، الاتصال ضعيف"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"قمر صناعي، الاتصال جيد"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"قمر صناعي، الاتصال متوفّر"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"اتصالات الطوارئ بالقمر الصناعي"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ملف العمل"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"متعة للبعض وليس للجميع"</string>
<string name="tuner_warning" msgid="1861736288458481650">"‏توفر لك أداة ضبط واجهة مستخدم النظام طرقًا إضافية لتعديل واجهة مستخدم Android وتخصيصها. ويمكن أن تطرأ تغييرات على هذه الميزات التجريبية أو يمكن أن تتعطل هذه الميزات أو تختفي في الإصدارات المستقبلية. عليك متابعة الاستخدام مع توخي الحذر."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"إضافة بطاقة"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"الانتقال إلى <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"الإضافة إلى الموضع <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"الموضِع غير صالح."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"الموضع: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"تمت إضافة البطاقة."</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"تمت إزالة البطاقة."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 0a4c4db04b25..16cd64b5d419 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -461,6 +461,10 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ৱিজেট কাষ্টমাইজ কৰক"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"লক স্ক্ৰীনত ৱিজেট"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ৱিজেট বাছনি কৰক"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুল-ডাউনৰ মেনু"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
@@ -629,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s আনমিউট কৰক"</string>
<string name="media_output_label_title" msgid="872824698593182505">"ইয়াত <xliff:g id="LABEL">%s</xliff:g> প্লে’ হৈ আছে"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"অডিঅ’ ইয়াত প্লে’ হ’ব"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"কল চলি আছে"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"স্থিতি দণ্ড"</string>
<string name="demo_mode" msgid="263484519766901593">"ছিষ্টেমৰ UI প্ৰদৰ্শন ম\'ড"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index f4b69b61471a..69cec1c6d115 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"İş profilində <xliff:g id="APP">%1$s</xliff:g> tətbiqində saxlanıb"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Şəxsi profildə <xliff:g id="APP">%1$s</xliff:g> tətbiqində yadda saxlanılıb"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fayllar"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> bu skrinşotu aşkarladı."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> və digər açıq tətbiqlər bu skrinşotu aşkarladı."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Kilid ekranında vidcetləri bağlayın"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Vidcetləri fərdiləşdirin"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Kilid ekranındakı vidcetlər"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vidcet seçin"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aşağı çəkilən menyu"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s seçimini səssiz rejimdən çıxarın"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> tətbiqində oxudulur"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio oxudulacaq"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Zəng edilir"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"Status paneli"</string>
<string name="demo_mode" msgid="263484519766901593">"Sistem interfeysi: demorejim"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Peyk, bağlantı zəifdir"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Peyk, bağlantı yaxşıdır"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Peyk, bağlantı var"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Təcili peyk bağlantısı"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"İş profili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Hamı üçün deyil, bəziləri üçün əyləncəli"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner Android istifadəçi interfeysini dəyişdirmək və fərdiləşdirmək üçün Sizə ekstra yollar təklif edir."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lövhə əlavə edin"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə köçürün"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə əlavə edin"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Mövqe yanlışdır."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Mozaik əlavə edilib"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Mozaik silinib"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 47df2fa55393..c2cc34afa758 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Sačuvano je u aplikaciji <xliff:g id="APP">%1$s</xliff:g> na poslovnom profilu"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Sačuvano je u aplikaciji <xliff:g id="APP">%1$s</xliff:g> na privatnom profilu"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fajlovi"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> je otkrila ovaj snimak ekrana."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> i druge otvorene aplikacije su otkrile ovaj snimak ekrana."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Zatvorite vidžete na zaključanom ekranu"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagodite vidžete"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Vidžeti na zaključanom ekranu"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"izaberite vidžet"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, veza je loša"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, veza je dobra"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć preko satelita"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Tjuner za korisnički interfejs sistema vam pruža dodatne načine za podešavanje i prilagođavanje Android korisničkog interfejsa. Ove eksperimentalne funkcije mogu da se promene, otkažu ili nestanu u budućim izdanjima. Budite oprezni."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodajte pločicu"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premestite na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajte na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozicija je nevažeća."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Pločica je dodata"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Pločica je uklonjena"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 8f080f908a7e..f956c0fc20a0 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -463,6 +463,10 @@
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Віджэты на экране блакіроўкі"</string>
<!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
<skip />
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"высоўнае меню"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
@@ -631,8 +635,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"уключыць гук (%s)"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> прайграецца тут:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Аўдыявыхад:"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ідзе выклік"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Наладка сістэмнага інтэрфейсу карыстальніка"</string>
<string name="status_bar" msgid="4357390266055077437">"Панэль стану"</string>
<string name="demo_mode" msgid="263484519766901593">"Рэжым дэманстрацыі сістэмнага інтэрфейсу карыстальніка"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 08a643db9240..c9d0cd220b82 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Запазена в(ъв) <xliff:g id="APP">%1$s</xliff:g> в служебния потребителски профил"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Запазена в(ъв) <xliff:g id="APP">%1$s</xliff:g> в личния потребителски профил"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> установи заснемането на тази екранна снимка."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> и други отворени приложения установиха заснемането на тази екранна снимка."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Затваряне на приспособленията на заключения екран"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Персонализиране на приспособленията"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Приспособления на заключения екран"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"избиране на приспособление"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падащо меню"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"включване на звука на %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Възпроизвеждане на <xliff:g id="LABEL">%s</xliff:g> на"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Аудиото ще се възпроизвежда на"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Активно обаждане"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Тунер на системния потребителски интерфейс"</string>
<string name="status_bar" msgid="4357390266055077437">"Лента на състоянието"</string>
<string name="demo_mode" msgid="263484519766901593">"Демонстрационен режим на системния ПИ"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Сателит, лоша връзка"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Сателит, добра връзка"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Сателит, налице е връзка"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS чрез сателит"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Потребителски профил в Work"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Забавно – но не за всички"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Тунерът на системния потребителски интерфейс ви предоставя допълнителни възможности за прецизиране и персонализиране на практическата работа с Android. Тези експериментални функции може да се променят, повредят или да изчезнат в бъдещите версии. Действайте внимателно."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Добавяне на панел"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместване към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавяне към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Невалидна позиция."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Панелът е добавен"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Панелът е премахнат"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index cd008529df0d..e2b4a6ddefe7 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"অফিস প্রোফাইলের মধ্যে <xliff:g id="APP">%1$s</xliff:g>-এ সেভ করা হয়েছে"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"<xliff:g id="APP">%1$s</xliff:g>-এ ব্যক্তিগত প্রোফাইলে সেভ করা হয়েছে"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ফাইল"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g>, এই স্ক্রিনশট শনাক্ত করেছে।"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> এবং খোলা থাকা অন্য অ্যাপ এই স্ক্রিনশট শনাক্ত করেছে।"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"লক স্ক্রিনে উইজেট বন্ধ করুন"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"উইজেট কাস্টমাইজ করুন"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"লক স্ক্রিনে উইজেট"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"উইজেট বেছে নিন"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুলডাউন মেনু"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"স্যাটেলাইট, খারাপ কানেকশন"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"স্যাটেলাইট, ভালো কানেকশন"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"স্যাটেলাইট, কানেকশন উপলভ্য আছে"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"স্যাটেলাইট SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"কাজের প্রোফাইল"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"কিছু ব্যক্তির জন্য মজাদার কিন্তু সকলের জন্য নয়"</string>
<string name="tuner_warning" msgid="1861736288458481650">"এই পরীক্ষামূলক বৈশিষ্ট্যগুলি ভবিষ্যতের সংস্করণগুলির মধ্যে পরিবর্তিত, বিভাজিত এবং অদৃশ্য হয়ে যেতে পারে৷ সাবধানতার সাথে এগিয়ে যান৷ সিস্টেম UI টিউনার আপনাকে Android ব্যবহারকারী ইন্টারফেসের সূক্ষ্ম সমন্বয় এবং কাস্টমাইজ করার অতিরিক্ত উপায়গুলি প্রদান করে৷"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"টাইল যোগ করুন"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>-এ সরান"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"অবস্থান <xliff:g id="POSITION">%1$d</xliff:g>-এ যোগ করুন"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"পজিশন সঠিক নয়।"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"অবস্থান <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"টাইল যোগ করা হয়েছে"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"টাইল সরানো হয়েছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index a0c13f08ce2f..108bed8df6d1 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Sačuvano je u aplikaciji <xliff:g id="APP">%1$s</xliff:g> na radnom profilu"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Sačuvano je u aplikaciji <xliff:g id="APP">%1$s</xliff:g> na privatnom profilu"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fajlovi"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> je otkrila ovaj snimak ekrana."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> i druge otvorene aplikacije su otkrile ovaj snimak ekrana."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Zatvaranje vidžeta na zaključanom ekranu"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagođavanje vidžeta"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Vidžeti na zaključanom ekranu"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"odabir vidžeta"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, slaba veza"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra veza"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć putem satelita"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Radni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Podešavač za korisnički interfejs sistema vam omogućava dodatne načine da podesite i prilagodite Androidov interfejs. Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodavanje kartice"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pomjeranje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nevažeći položaj."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartica je dodana"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartica je uklonjena"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0c5d51df6011..48fadbc5e8c7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"S\'ha desat al perfil de treball de <xliff:g id="APP">%1$s</xliff:g>"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"S\'ha desat a <xliff:g id="APP">%1$s</xliff:g> al perfil privat"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fitxers"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ha detectat aquesta captura de pantalla."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> i altres aplicacions obertes han detectat aquesta captura de pantalla."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Tanca els widgets a la pantalla de bloqueig"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalitza els widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets a la pantalla de bloqueig"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecciona el widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satèl·lit, connexió deficient"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satèl·lit, bona connexió"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satèl·lit, connexió disponible"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS per satèl·lit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de treball"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversió per a uns quants, però no per a tothom"</string>
<string name="tuner_warning" msgid="1861736288458481650">"El Personalitzador d\'interfície d\'usuari presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Afegeix una icona"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mou a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Afegeix a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"La posició no és vàlida."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"El mosaic s\'ha afegit"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"El mosaic s\'ha suprimit"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index f0aa2c0f657b..c90a0230aa31 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Uloženo v aplikaci <xliff:g id="APP">%1$s</xliff:g> v pracovním profilu"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Uloženo do aplikace <xliff:g id="APP">%1$s</xliff:g> v soukromém profilu"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Soubory"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikace <xliff:g id="APPNAME">%1$s</xliff:g> objevila tento snímek obrazovky."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> a ostatní otevřené aplikace objevily tento snímek obrazovky."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Zavřít widgety na obrazovce uzamčení"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Přizpůsobit widgety"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgety na obrazovce uzamčení"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vybrat widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbalovací nabídka"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, špatné připojení"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobré připojení"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, připojení je k dispozici"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS přes satelit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Pracovní profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zábava, která není pro každého"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Nástroj na ladění uživatelského rozhraní systému vám nabízí další způsoby, jak si vyladit a přizpůsobit uživatelské rozhraní Android. Tyto experimentální funkce mohou v dalších verzích chybět, nefungovat nebo být změněny. Postupujte proto prosím opatrně."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Přidat dlaždici"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Přesunout na pozici <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Přidat dlaždici na pozici <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozice není platná."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Karta byla přidána"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Karta byla odstraněna"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 5191ef25c245..036f855b7a8f 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Gemt i <xliff:g id="APP">%1$s</xliff:g> på arbejdsprofilen"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Gemt i <xliff:g id="APP">%1$s</xliff:g> på den private profil"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Filer"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> har registreret dette screenshot."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og andre åbne apps har registreret dette screenshot."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Luk widgets på låseskærmen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tilpas widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets på låseskærmen"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vælg widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullemenu"</string>
@@ -592,7 +594,7 @@
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nej tak"</string>
<string name="screen_pinning_start" msgid="7483998671383371313">"Appen er fastgjort"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"Appen er frigjort"</string>
- <string name="stream_voice_call" msgid="7468348170702375660">"Ring op"</string>
+ <string name="stream_voice_call" msgid="7468348170702375660">"Opkald"</string>
<string name="stream_system" msgid="7663148785370565134">"System"</string>
<string name="stream_ring" msgid="7550670036738697526">"Ringetone"</string>
<string name="stream_music" msgid="2188224742361847580">"Medie"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"slå lyden til for %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Afspiller <xliff:g id="LABEL">%s</xliff:g> på"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Lyden afspilles på"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ringer på"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"Statusbjælke"</string>
<string name="demo_mode" msgid="263484519766901593">"Demotilstand for systemets brugerflade"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellit – dårlig forbindelse"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit – god forbindelse"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit – forbindelsen er tilgængelig"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-meldinger via satellit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Arbejdsprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Sjovt for nogle, men ikke for alle"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner giver dig flere muligheder for at justere og tilpasse Android-brugerfladen. Disse eksperimentelle funktioner kan ændres, gå i stykker eller forsvinde i fremtidige udgivelser. Vær forsigtig, hvis du fortsætter."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tilføj felt"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flyt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Føj til lokation <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positionen er ugyldig."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Lokation <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Feltet blev tilføjet"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Feltet blev fjernet"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b427f345bba2..42efdc22f1db 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"In <xliff:g id="APP">%1$s</xliff:g> im Arbeitsprofil gespeichert"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Im vertraulichen Profil in <xliff:g id="APP">%1$s</xliff:g> gespeichert"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Dateien"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> hat diesen Screenshot erkannt."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> und andere geöffnete Apps haben diesen Screenshot erkannt."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Widgets auf dem Sperrbildschirm schließen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Widgets anpassen"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets auf dem Sperrbildschirm"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"Widget auswählen"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellit, Verbindung schlecht"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit, Verbindung gut"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, Verbindung verfügbar"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Notruf über Satellit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Arbeitsprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Für einige ein Vergnügen, aber nicht für alle"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Mit System UI Tuner erhältst du zusätzliche Möglichkeiten, die Android-Benutzeroberfläche anzupassen. Achtung: Diese Testfunktionen können sich ändern, abstürzen oder in zukünftigen Versionen verschwinden."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Kachel hinzufügen"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Auf Position <xliff:g id="POSITION">%1$d</xliff:g> verschieben"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Zur Position <xliff:g id="POSITION">%1$d</xliff:g> hinzufügen"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position ist ungültig."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ansicht hinzugefügt"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ansicht entfernt"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8e3a0ea74a58..72ab8848c6ad 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Αποθηκεύτηκε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> στο προφίλ εργασίας"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Αποθηκεύτηκε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> στο ιδιωτικό προφίλ"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Αρχεία"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Η εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g> εντόπισε αυτό το στιγμιότυπο οθόνης."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Η εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g> και άλλες ανοικτές εφαρμογές εντόπισαν το στιγμιότυπο οθόνης."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Κλείσιμο γραφικών στοιχείων στην οθόνη κλειδώματος"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Προσαρμογή γραφικών στοιχείων"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Γραφικά στοιχεία στην οθόνη κλειδώματος"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"επιλογή γραφικού στοιχείου"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"αναπτυσσόμενο μενού"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Δορυφορική, κακή σύνδεση"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Δορυφορική, καλή σύνδεση"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Δορυφορική, διαθέσιμη σύνδεση"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Δορυφορικό SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Προφίλ εργασίας"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Διασκέδαση για ορισμένους, αλλά όχι για όλους"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Το System UI Tuner σάς προσφέρει επιπλέον τρόπους για να τροποποιήσετε και να προσαρμόσετε τη διεπαφή χρήστη Android. Αυτές οι πειραματικές λειτουργίες ενδέχεται να τροποποιηθούν, να παρουσιάσουν σφάλματα ή να καταργηθούν σε μελλοντικές εκδόσεις. Συνεχίστε με προσοχή."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Προσθήκη πλακιδίου"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Μετακίνηση στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Προσθήκη στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Μη έγκυρη θέση."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Το πλακίδιο προστέθηκε"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Το πλακίδιο καταργήθηκε"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e24ec05a455d..e414cd4e857a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Saved in <xliff:g id="APP">%1$s</xliff:g> in the work profile"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Saved in <xliff:g id="APP">%1$s</xliff:g> in the private profile"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> detected this screenshot."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Close widgets on lock screen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Customise widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets on lock screen"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"select widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellite, poor connection"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner gives you extra ways to tweak and customise the Android user interface. These experimental features may change, break or disappear in future releases. Proceed with caution."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Add tile"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Move to <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 366fc1fff731..204f21d0c23a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -461,6 +461,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Customize widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets on lock screen"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"select widget"</string>
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"remove widget"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"place selected widget"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e24ec05a455d..e414cd4e857a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Saved in <xliff:g id="APP">%1$s</xliff:g> in the work profile"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Saved in <xliff:g id="APP">%1$s</xliff:g> in the private profile"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> detected this screenshot."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Close widgets on lock screen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Customise widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets on lock screen"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"select widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellite, poor connection"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner gives you extra ways to tweak and customise the Android user interface. These experimental features may change, break or disappear in future releases. Proceed with caution."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Add tile"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Move to <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e24ec05a455d..e414cd4e857a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Saved in <xliff:g id="APP">%1$s</xliff:g> in the work profile"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Saved in <xliff:g id="APP">%1$s</xliff:g> in the private profile"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> detected this screenshot."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Close widgets on lock screen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Customise widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets on lock screen"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"select widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellite, poor connection"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner gives you extra ways to tweak and customise the Android user interface. These experimental features may change, break or disappear in future releases. Proceed with caution."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Add tile"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Move to <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 2aa82e0e3c2c..ee28a624b462 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -461,6 +461,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎Customize widgets‎‏‎‎‏‎"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎Widgets on lock screen‎‏‎‎‏‎"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎select widget‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎remove widget‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎place selected widget‎‏‎‎‏‎"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‎Switch user‎‏‎‎‏‎"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎pulldown menu‎‏‎‎‏‎"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎All apps and data in this session will be deleted.‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e01c327e9863..42424efdbeb6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Se guardó en <xliff:g id="APP">%1$s</xliff:g> en el perfil de trabajo"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Guardada en <xliff:g id="APP">%1$s</xliff:g> en el perfil personal"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Archivos"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> detectó que tomaste una captura de pantalla."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> y otras apps en ejecución detectaron que tomaste una captura de pantalla."</string>
@@ -276,7 +275,7 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Guardado"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activar"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Volver a activar automáticamente mañana"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Activar automáticamente mañana"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Las funciones como Quick Share y Encontrar mi dispositivo usan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth se activará mañana a la mañana"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Uso compartido de audio"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Cerrar widgets en la pantalla de bloqueo"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets en la pantalla de bloqueo"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"Seleccionar widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú expandible"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satélite, conexión inestable"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, buena conexión"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión disponible"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabajo"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversión para algunos, pero no para todos"</string>
<string name="tuner_warning" msgid="1861736288458481650">"El sintonizador de IU del sistema te brinda más formas para editar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, dejar de funcionar o no incluirse en futuras versiones. Procede con precaución."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Agregar tarjeta"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Agregar a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición no válida"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Se agregó la tarjeta"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Se quitó la tarjeta"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e6d3599404a9..77989e4ac7d3 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -461,6 +461,10 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets en la pantalla de bloqueo"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"seleccionar widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 65b1908c1187..a3663a0bd958 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Salvestati tööprofiilil rakendusse <xliff:g id="APP">%1$s</xliff:g>"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Salvestati privaatsel profiilil rakendusse <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> tuvastas selle ekraanipildi."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ja muud avatud rakendused tuvastasid selle ekraanipildi."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Lukustuskuva vidinate sulgemine"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Kohanda vidinaid"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Lukustuskuva vidinad"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vidina valimine"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rippmenüü"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelliit, kehv ühendus"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliit, hea ühendus"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliit, ühendus on saadaval"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliit-SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Tööprofiil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Kõik ei pruugi sellest rõõmu tunda"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Süsteemi kasutajaliidese tuuner pakub täiendavaid võimalusi Androidi kasutajaliidese muutmiseks ja kohandamiseks. Need katselised funktsioonid võivad muutuda, rikki minna või tulevastest versioonidest kaduda. Olge jätkamisel ettevaatlik."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lisa paan"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Teisaldamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Sobimatu asukoht."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Asend <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Paan on lisatud"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Paan on eemaldatud"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 23398471c6d3..23de72ea0527 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Laneko profilaren <xliff:g id="APP">%1$s</xliff:g> aplikazioan gorde da"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Profil pribatuaren <xliff:g id="APP">%1$s</xliff:g> aplikazioan gorde da"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fitxategiak"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak pantaila-argazkia hauteman du."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak eta irekitako beste aplikazio batzuek pantaila-argazkia hauteman dute."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Itxi pantaila blokeatuko widgetak"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Pertsonalizatu widgetak"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Pantaila blokeatuko widgetak"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"hautatu widget bat"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"zabaldu menua"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelitea, konexio ahula"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelitea, konexio ona"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelitea, konexioa erabilgarri"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelite bidezko SOS komunikazioa"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Laneko profila"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Dibertsioa batzuentzat, baina ez guztientzat"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Sistemaren erabiltzaile-interfazearen konfiguratzaileak Android erabiltzaile-interfazea moldatzeko eta pertsonalizatzeko modu gehiago eskaintzen dizkizu. Baliteke eginbide esperimental horiek hurrengo kaleratzeetan aldatuta, etenda edo desagertuta egotea. Kontuz erabili."</string>
@@ -776,8 +777,8 @@
<string name="group_system_go_back" msgid="2730322046244918816">"Egin atzera"</string>
<string name="group_system_access_home_screen" msgid="4130366993484706483">"Joan orri nagusira"</string>
<string name="group_system_overview_open_apps" msgid="5659958952937994104">"Ikusi azkenaldiko aplikazioak"</string>
- <string name="group_system_cycle_forward" msgid="5478663965957647805">"Ikusi azken aplikazioak banan-banan (aurrerantz)"</string>
- <string name="group_system_cycle_back" msgid="8194102916946802902">"Ikusi azken aplikazioak banan-banan (atzerantz)"</string>
+ <string name="group_system_cycle_forward" msgid="5478663965957647805">"Ikusi azkenaldiko aplikazioak banan-banan (aurrerantz)"</string>
+ <string name="group_system_cycle_back" msgid="8194102916946802902">"Ikusi azkenaldiko aplikazioak banan-banan (atzerantz)"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ireki aplikazioen zerrenda"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ireki ezarpenak"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ireki Laguntzailea"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Gehitu lauza"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Eraman <xliff:g id="POSITION">%1$d</xliff:g>garren lekura"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Gehitu <xliff:g id="POSITION">%1$d</xliff:g>garren lekuan"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Kokapenak ez du balio."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>garren lekua"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Gehitu da lauza"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kendu da lauza"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ad22bcc8cb51..9feeaeeec31a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"در برنامه <xliff:g id="APP">%1$s</xliff:g> در نمایه کاری ذخیره شد"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"در برنامه <xliff:g id="APP">%1$s</xliff:g> در نمایه خصوصی ذخیره شد"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"‫«<xliff:g id="APPNAME">%1$s</xliff:g>» این نماگرفت را تشخیص داد."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> و سایر برنامه‌های باز این نماگرفت را تشخیص دادند."</string>
@@ -189,7 +188,7 @@
<string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"اگر در تلاش بعدی‌ پین نادرستی وارد کنید، نمایه کاری شما و داده‌های آن حذف خواهند شد."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"اگر در تلاش بعدی‌ گذرواژه نادرستی وارد کنید، نمایه کاری شما و داده‌های آن حذف خواهند شد."</string>
<string name="biometric_re_enroll_dialog_confirm" msgid="3049858021857801836">"راه‌اندازی"</string>
- <string name="biometric_re_enroll_dialog_cancel" msgid="93760939407091417">"اکنون نه"</string>
+ <string name="biometric_re_enroll_dialog_cancel" msgid="93760939407091417">"حالا نه"</string>
<string name="biometric_re_enroll_notification_content" msgid="8685925877186288180">"این کار برای بهبود امنیت و عملکرد لازم است"</string>
<string name="fingerprint_re_enroll_notification_title" msgid="4539432429683916604">"راه‌اندازی مجدد «قفل‌گشایی با اثر انگشت»"</string>
<string name="fingerprint_re_enroll_notification_name" msgid="630798657797645704">"قفل‌گشایی با اثر انگشت"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"بستن ابزارک‌ها در صفحه قفل"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"سفارشی‌سازی ابزارک‌ها"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ابزارک‌ها در صفحه قفل"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"انتخاب ابزارک"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"منوی پایین‌پر"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ماهواره، اتصال ضعیف است"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ماهواره، اتصال خوب است"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ماهواره، اتصال دردسترس است"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"درخواست کمک ماهواره‌ای"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"نمایه کاری"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"برای بعضی افراد سرگرم‌کننده است اما نه برای همه"</string>
<string name="tuner_warning" msgid="1861736288458481650">"‏«تنظیم‌کننده واسط کاربری سیستم» روش‌های بیشتری برای تنظیم دقیق و سفارشی کردن واسط کاربری Android در اختیار شما قرار می‌دهد. ممکن است این ویژگی‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده جود نداشته باشند. با احتیاط ادامه دهید."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"افزودن کاشی"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"انتقال به <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"افزودن به موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"موقعیت نامعتبر است."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"کاشی اضافه شد"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"کاشی حذف شد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 5928cf81802c..68319fd8b4b6 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Tallennettu työprofiiliin tässä sovelluksessa: <xliff:g id="APP">%1$s</xliff:g>"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Tallennettu yksityiseen profiiliin tässä sovelluksessa: <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> havaitsi tämän kuvakaappauksen."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ja jotkin muut sovellukset havaitsivat tämän kuvakaappauksen."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Sulje widgetit lukitusnäytöllä"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Muokkaa widgetejä"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgetit lukitusnäytöllä"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"valitse widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelliitti, huono yhteys"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliitti, hyvä yhteys"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliitti, yhteys saatavilla"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Työprofiili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Ei sovellu kaikkien käyttöön"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner antaa lisämahdollisuuksia Android-käyttöliittymän muokkaamiseen. Nämä kokeelliset ominaisuudet voivat muuttua, lakata toimimasta tai kadota milloin tahansa. Jatka omalla vastuullasi."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lisää kiekko"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Siirrä paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisää paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Virheellinen sijainti."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kiekko lisätty"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kiekko poistettu"</string>
@@ -923,7 +923,7 @@
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois päältä"</string>
- <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ei ole käytössä"</string>
+ <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth on pois päältä"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"Älä häiritse ‑tila on pois päältä"</string>
<string name="dnd_is_on" msgid="7009368176361546279">"Älä häiritse ‑tila on käytössä"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Automaattinen sääntö otti käyttöön Älä häiritse ‑tilan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 8cb63ea20b59..fd6ec7a371b8 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Enregistré dans <xliff:g id="APP">%1$s</xliff:g> dans le profil professionnel"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Enregistré dans <xliff:g id="APP">%1$s</xliff:g> dans le profil privé"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fichiers"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> a détecté cette capture d\'écran."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> et d\'autres applications ouvertes ont détecté cette capture d\'écran."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Fermer les widgets sur l\'écran de verrouillage"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personnaliser les widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets sur l\'écran de verrouillage"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"sélectionner le widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Connexion satellite faible"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Bonne connexion satellite"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite accessible"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner vous propose de nouvelles manières d\'adapter et de personnaliser l\'interface utilisateur d\'Android. Ces fonctionnalités expérimentales peuvent être modifiées, cesser de fonctionner ou disparaître dans les versions futures. À utiliser avec prudence."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter la tuile"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Déplacer vers <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position incorrecte."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tuile ajoutée"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tuile retirée"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index fd11a11f4c90..47f469ff4605 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Enregistré dans <xliff:g id="APP">%1$s</xliff:g>, dans le profil professionnel"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Enregistré dans <xliff:g id="APP">%1$s</xliff:g> dans le profil privé"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fichiers"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> a détecté cette capture d\'écran."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> et d\'autres applis ouvertes ont détecté cette capture d\'écran."</string>
@@ -267,7 +266,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne pas déranger"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Aucun appareil associé disponible."</string>
- <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Appuyer pour connecter ou déconnecter un appareil"</string>
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Appuyez pour connecter ou déconnecter un appareil"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Associer un nouvel appareil"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Tout afficher"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Utiliser le Bluetooth"</string>
@@ -369,7 +368,7 @@
<string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
<string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Moyen"</string>
<string name="quick_settings_contrast_high" msgid="656049259587494499">"Élevé"</string>
- <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Prothèses auditives"</string>
+ <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquer pour associer un nouvel appareil"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Fermer les widgets sur l\'écran de verrouillage"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personnaliser les widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets sur l\'écran de verrouillage"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"sélectionner un widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"réactiver le son de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Diffusion de <xliff:g id="LABEL">%s</xliff:g> sur"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Lecture audio sur"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Appel défini sur"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"Barre d\'état"</string>
<string name="demo_mode" msgid="263484519766901593">"Mode démo de l\'UI du système"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Mauvaise connexion satellite"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Bonne connexion satellite"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite disponible"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner vous propose de nouvelles manières d\'adapter et de personnaliser l\'interface utilisateur Android. Ces fonctionnalités expérimentales peuvent être modifiées, cesser de fonctionner ou disparaître dans les versions futures. À utiliser avec prudence."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter un bloc"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Déplacer vers <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Emplacement non valide."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloc ajouté"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloc supprimé"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 5589e3ac6a33..e7037b39fe33 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Captura de pantalla gardada na aplicación <xliff:g id="APP">%1$s</xliff:g> do perfil de traballo"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Gardouse na aplicación <xliff:g id="APP">%1$s</xliff:g> do perfil privado"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ficheiros"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> detectou esta captura de pantalla."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e outras aplicacións abertas detectaron esta captura de pantalla."</string>
@@ -371,7 +370,7 @@
<string name="quick_settings_contrast_high" msgid="656049259587494499">"Nivel alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
- <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular un dispositivo novo"</string>
+ <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo novo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic para vincular un novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Non se puido actualizar a configuración predeterminada"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Queres desbloquear o micrófono do dispositivo?"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Ocultar os widgets na pantalla de bloqueo"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar os widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets na pantalla de bloqueo"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"seleccionar widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú despregable"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satélite, mala conexión"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, boa conexión"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión dispoñible"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de traballo"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversión só para algúns"</string>
<string name="tuner_warning" msgid="1861736288458481650">"O configurador da IU do sistema ofréceche formas adicionais de modificar e personalizar a interface de usuario de Android. Estas funcións experimentais poden cambiar, interromperse ou desaparecer en futuras versións. Continúa con precaución."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Engadir tarxeta"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engadir á posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición non válida."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Engadiuse a tarxeta"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Quitouse a tarxeta"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 58b4f9b78b8e..b3c8e1eb5a88 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"ઑફિસની પ્રોફાઇલમાં <xliff:g id="APP">%1$s</xliff:g>માં સાચવવામાં આવ્યો"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"<xliff:g id="APP">%1$s</xliff:g>માં ખાનગી પ્રોફાઇલમાં સાચવવામાં આવ્યો"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ફાઇલો"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> દ્વારા આ સ્ક્રીનશૉટ લેવાયાની ભાળ મેળવવામાં આવી."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> અને કામ કરતી અન્ય ઍપ દ્વારા આ સ્ક્રીનશૉટ લેવાયાની ભાળ મેળવવામાં આવી."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"લૉક સ્ક્રીન પર વિજેટ બંધ કરો"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"વિજેટ કસ્ટમાઇઝ કરો"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"લૉક સ્ક્રીન પર વિજેટ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"વિજેટ પસંદ કરો"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"પુલડાઉન મેનૂ"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%sને અનમ્યૂટ કરો"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> વગાડી રહ્યાં છીએ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ઑડિયો આની પર વાગશે"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"કૉલ ચાલુ છે"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"સિસ્ટમ UI ટ્યૂનર"</string>
<string name="status_bar" msgid="4357390266055077437">"સ્ટેટસ બાર"</string>
<string name="demo_mode" msgid="263484519766901593">"સિસ્ટમ UI ડેમો મોડ"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"સૅટલાઇટ, નબળું કનેક્શન"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"સૅટલાઇટ, સારું કનેક્શન"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"સૅટલાઇટ, કનેક્શન ઉપલબ્ધ છે"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ઇમર્જન્સી સૅટલાઇટ સહાય"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ઑફિસની પ્રોફાઇલ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"કેટલાક માટે મજા પરંતુ બધા માટે નહીં"</string>
<string name="tuner_warning" msgid="1861736288458481650">"સિસ્ટમ UI ટ્યૂનર તમને Android વપરાશકર્તા ઇન્ટરફેસને ટ્વીક અને કસ્ટમાઇઝ કરવાની વધારાની રીતો આપે છે. ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ટાઇલ ઉમેરો"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> પર ખસેડો"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"જગ્યા પર <xliff:g id="POSITION">%1$d</xliff:g> ઉમેરો"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"સ્થિતિ અમાન્ય છે."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"જગ્યા <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ટાઇલ ઉમેરી"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ટાઇલ કાઢી નાખી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 681ead97c47f..28825845bb08 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"वर्क प्रोफ़ाइल में मौजूद <xliff:g id="APP">%1$s</xliff:g> में सेव किया गया है"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"स्क्रीनशॉट को <xliff:g id="APP">%1$s</xliff:g> की निजी प्रोफ़ाइल में सेव किया गया"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> को इस स्क्रीनशॉट का पता चला है."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> और खुले हुए अन्य ऐप्लिकेशन को इस स्क्रीनशॉट का पता चला है."</string>
@@ -276,7 +275,7 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"सेव किया गया"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"डिसकनेक्ट करें"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"चालू करें"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"कल फिर से अपने-आप चालू हो जाएगा"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"कल फिर से अपने-आप चालू हो जाए"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक शेयर और Find My Device जैसी सुविधाएं, ब्लूटूथ का इस्तेमाल करती हैं"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लूटूथ कल सुबह चालू होगा"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ऑडियो शेयर करने की सुविधा"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"लॉक स्क्रीन पर विजेट बंद करें"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"विजेट अपनी पसंद के मुताबिक बनाएं"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"लॉक स्क्रीन पर विजेट"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"विजेट चुनें"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेन्यू"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"सैटलाइट कनेक्शन खराब है"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"सैटलाइट कनेक्शन अच्छा है"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"सैटलाइट कनेक्शन उपलब्ध है"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"सैटलाइट एसओएस"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"वर्क प्रोफ़ाइल"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"कुछ के लिए मज़ेदार लेकिन सबके लिए नहीं"</string>
<string name="tuner_warning" msgid="1861736288458481650">"सिस्टम यूज़र इंटरफ़ेस (यूआई) ट्यूनर, आपको Android यूज़र इंटरफ़ेस में सुधार लाने और उसे अपनी पसंद के हिसाब से बदलने के कुछ और तरीके देता है. प्रयोग के तौर पर इस्तेमाल हो रहीं ये सुविधाएं आगे चल कर रिलीज़ की जा सकती हैं, रोकी जा सकती हैं या दिखाई देना बंद हो सकती हैं. सावधानी से आगे बढ़ें."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"टाइल जोड़ें"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"टाइल को <xliff:g id="POSITION">%1$d</xliff:g> पोज़िशन पर ले जाएं"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"टाइल को <xliff:g id="POSITION">%1$d</xliff:g> पोज़िशन पर जोड़ें"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"मौजूदा जगह अमान्य है."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"टाइल की पोज़िशन <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल जोड़ी गई"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल हटाई गई"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index a55703673d37..560938bb882b 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Spremljeno u aplikaciju <xliff:g id="APP">%1$s</xliff:g> u poslovnom profilu"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Spremljeno u aplikaciju <xliff:g id="APP">%1$s</xliff:g> na privatnom profilu"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Datoteke"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> otkrila je ovu snimku zaslona."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> i druge otvorene aplikacije otkrile su ovu snimku zaslona."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Zatvaranje widgeta na zaključanom zaslonu"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagodi widgete"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgeti na zaključanom zaslonu"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"odaberi widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string>
@@ -592,9 +594,9 @@
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ne, hvala"</string>
<string name="screen_pinning_start" msgid="7483998671383371313">"Aplikacija je prikvačena"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"Aplikacija je otkvačena"</string>
- <string name="stream_voice_call" msgid="7468348170702375660">"Nazovi"</string>
+ <string name="stream_voice_call" msgid="7468348170702375660">"Poziv"</string>
<string name="stream_system" msgid="7663148785370565134">"Sustav"</string>
- <string name="stream_ring" msgid="7550670036738697526">"Zvoni"</string>
+ <string name="stream_ring" msgid="7550670036738697526">"Zvonjenje"</string>
<string name="stream_music" msgid="2188224742361847580">"Mediji"</string>
<string name="stream_alarm" msgid="16058075093011694">"Alarm"</string>
<string name="stream_notification" msgid="7930294049046243939">"Obavijest"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, slaba veza"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra veza"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS putem satelita"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Ugađanje korisničkog sučelja sustava pruža vam dodatne načine za prilagodbu korisničkog sučelja Androida. Te se eksperimentalne značajke mogu promijeniti, prekinuti ili nestati u budućim izdanjima. Nastavite uz oprez."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodavanje kartice"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premještanje u prostoriju <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Položaj nije važeći."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartica je dodana"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartica je uklonjena"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 06c9ff6ea0ba..23166431bb28 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Mentve a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás munkaprofiljába"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Mentve a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás privát profiljában"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fájlok"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> észlelte ezt a képernyőképet."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> és más nyitott alkalmazások észlelték ezt a képernyőképet."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"A lezárási képernyőn lévő modulok bezárása"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Modulok személyre szabása"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Modulok a lezárási képernyőn"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"modul kiválasztása"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"lehúzható menü"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Műhold, gyenge kapcsolat"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Műhold, jó kapcsolat"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Műhold, van rendelkezésre álló kapcsolat"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Műholdas SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Munkaprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Egyeseknek tetszik, másoknak nem"</string>
<string name="tuner_warning" msgid="1861736288458481650">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Mozaik hozzáadása"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Áthelyezés ide: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Hozzáadás a következő pozícióhoz: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Érvénytelen pozíció."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. hely"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kártya hozzáadva"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kártya eltávolítva"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index ff2f4df6b201..3d70b70556ab 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Սքրինշոթը պահվեց <xliff:g id="APP">%1$s</xliff:g>-ի աշխատանքային պրոֆիլում"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Սքրինշոթը պահվեց <xliff:g id="APP">%1$s</xliff:g>-ի անձնական պրոֆիլում"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ֆայլեր"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը հայտնաբերել է այս սքրինշոթը։"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g>-ն ու բացված այլ հավելվածներ հայտնաբերել են այս սքրինշոթը։"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Փակել վիջեթները կողպէկրանին"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Հարմարեցնել վիջեթները"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Վիջեթներ կողպէկրանին"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ընտրել վիջեթ"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Արբանյակային թույլ կապ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Արբանյակային լավ կապ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Հասանելի է արբանյակային կապ"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Աշխատանքային պրոֆիլ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Զվարճանք մեկ՝ որոշակի մարդու համար"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Համակարգի ՕՄ-ի կարգավորիչը հնարավորություն է տալիս հարմարեցնել Android-ի օգտատիրոջ միջերեսը: Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ավելացնել սալիկ"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Տեղափոխել դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ավելացնել դիրք <xliff:g id="POSITION">%1$d</xliff:g>-ում"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Դիրքն անվավեր է։"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Սալիկն ավելացվեց"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Սալիկը հեռացվեց"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 1aa3d9f650cb..bc7bb0fcd6a4 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Disimpan di <xliff:g id="APP">%1$s</xliff:g> di profil kerja"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Disimpan di <xliff:g id="APP">%1$s</xliff:g> di profil pribadi"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"File"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> mendeteksi screenshot ini."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> dan aplikasi terbuka lainnya mendeteksi screenshot ini."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Tutup widget di layar kunci"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Sesuaikan widget"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widget di layar kunci"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pilih widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pulldown"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, koneksi buruk"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, koneksi baik"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, koneksi tersedia"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil kerja"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Tidak semua orang menganggapnya baik"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Penyetel Antarmuka Pengguna Sistem memberikan cara tambahan untuk mengubah dan menyesuaikan antarmuka pengguna Android. Fitur eksperimental ini dapat berubah, rusak, atau menghilang dalam rilis di masa mendatang. Lanjutkan dengan hati-hati."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tambahkan kartu"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pindahkan ke <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan ke posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisi tidak valid."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartu ditambahkan"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartu dihapus"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 6ba831b96fcc..b30c89845138 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -461,6 +461,10 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Sérsníða græjur"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Græjur á lásskjá"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"velja græju"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5825be4e9d17..210209958ae9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Salvato nell\'app <xliff:g id="APP">%1$s</xliff:g> nel profilo di lavoro"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Salvato nel profilo privato nell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"File"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ha rilevato questo screenshot."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e altre app aperte hanno rilevato questo screenshot."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Chiudi widget su schermata di blocco"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizza widget"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widget su schermata di blocco"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"seleziona widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu a discesa"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellitare, connessione debole"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellitare, connessione buona"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitare, connessione disponibile"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satellitare"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profilo di lavoro"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Il divertimento riservato a pochi eletti"</string>
<string name="tuner_warning" msgid="1861736288458481650">"L\'Ottimizzatore UI di sistema mette a disposizione altri metodi per modificare e personalizzare l\'interfaccia utente di Android. Queste funzioni sperimentali potrebbero cambiare, interrompersi o scomparire nelle versioni successive. Procedi con cautela."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Aggiungi riquadro"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Sposta nella posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Aggiungi alla posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posizione non valida."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Riquadro aggiunto"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Riquadro rimosso"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 33b5db0753ec..5be4172db9d1 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"נשמר באפליקציה <xliff:g id="APP">%1$s</xliff:g> בתוך פרופיל העבודה"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"נשמר באפליקציה <xliff:g id="APP">%1$s</xliff:g> בפרופיל הפרטי"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"קבצים"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> זיהתה את צילום המסך הזה."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> ואפליקציות פתוחות נוספות זיהו את צילום המסך הזה."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"סגירת ווידג\'טים במסך הנעילה"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"התאמה אישית של ווידג\'טים"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ווידג\'טים במסך הנעילה"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"צריך לבחור ווידג\'ט"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"תפריט במשיכה למטה"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"לוויין, חיבור באיכות ירודה"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"לוויין, חיבור באיכות טובה"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"לוויין, יש חיבור זמין"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"תקשורת לוויינית למצב חירום"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"פרופיל עבודה"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"מהנה בשביל חלק מהאנשים, אבל לא בשביל כולם"</string>
<string name="tuner_warning" msgid="1861736288458481650">"‏התכונה System UI Tuner מספקת לך דרכים נוספות להתאים אישית את ממשק המשתמש של Android. התכונות הניסיוניות האלה עשויות להשתנות, לא לעבוד כראוי או להיעלם בגרסאות עתידיות. יש להמשיך בזהירות."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"הוספת לחצן"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"העברה למיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"הוספה למיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"המיקום לא תקין."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"הלחצן נוסף"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"הלחצן הוסר"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index ac8d81c45c2c..62a3a4324658 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -461,6 +461,10 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ウィジェットのカスタマイズ"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ロック画面のウィジェット"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ウィジェットを選択"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"プルダウン メニュー"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 7b7ee68c4367..2a4f5d68c1f7 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"შენახულია <xliff:g id="APP">%1$s</xliff:g>-ში სამსახურის პროფილში"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"შენახულია <xliff:g id="APP">%1$s</xliff:g>-ში, პირად პროფილში"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ფაილები"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g>-მა აღმოაჩინა ეკრანის ეს ანაბეჭდი"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g>-მა და სხვა გახსნილმა აპებმა აღმოაჩინეს ეკრანის ეს ანაბეჭდი."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ჩაკეტილ ეკრანზე ვიჯეტების დახურვა"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ვიჯეტების მორგება"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ვიჯეტები ჩაკეტილ ეკრანზე"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ვიჯეტის არჩევა"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ჩამოშლადი მენიუ"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s-ის დადუმების მოხსნა"</string>
<string name="media_output_label_title" msgid="872824698593182505">"უკრავს <xliff:g id="LABEL">%s</xliff:g>:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"აუდიო დაიკვრება"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"მიმდინარეობს ზარი"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"სისტემის UI ტუნერი"</string>
<string name="status_bar" msgid="4357390266055077437">"სტატუსის ზოლი"</string>
<string name="demo_mode" msgid="263484519766901593">"სისტემის UI-ს დემო-რეჟიმი"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"სუსტი სატელიტური კავშირი"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"კარგი სატელიტური კავშირი"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ხელმისაწვდომია სატელიტური კავშირი"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"სატელიტური SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"სამსახურის პროფილი"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ზოგისთვის გასართობია, მაგრამ არა ყველასთვის"</string>
<string name="tuner_warning" msgid="1861736288458481650">"სისტემის UI ტუნერი გაძლევთ დამატებით გზებს Android-ის სამომხმარებლო ინტერფეისის პარამეტრების დაყენებისთვის. ეს ექსპერიმენტული მახასიათებლები შეიძლება შეიცვალოს, შეწყდეს ან გაქრეს მომავალ ვერსიებში. სიფრთხილით გააგრძელეთ."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"მოზაიკის დამატება"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"გადატანა <xliff:g id="POSITION">%1$d</xliff:g>-ზე"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"დამატება პოზიციაზე <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"პოზიცია არასწორია."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"მოზაიკის ფილა დაემატა"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"მოზაიკის ფილა ამოიშალა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a3ba3d7588b9..398677ee6396 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Жұмыс профиліндегі <xliff:g id="APP">%1$s</xliff:g> қолданбасында сақталған."</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Жеке профильдегі <xliff:g id="APP">%1$s</xliff:g> қолданбасында сақталды."</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> қолданбасы осы скриншотты анықтады."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> және басқа да ашық қолданбалар осы скриншотты анықтады."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Құлыптаулы экранда виджеттерді жабу"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Виджеттерді бейімдеу"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Құлыптаулы экрандағы виджеттер"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виджет таңдау"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Жерсерік, байланыс нашар."</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Жерсерік, байланыс жақсы."</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Жерсерік, байланыс бар."</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Жұмыс профилі"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Кейбіреулерге қызық, бірақ барлығына емес"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Жүйелік пайдаланушылық интерфейс тюнері Android пайдаланушылық интерфейсін реттеудің қосымша жолдарын береді. Бұл эксперименттік мүмкіндіктер болашақ шығарылымдарда өзгеруі, бұзылуы немесе жоғалуы мүмкін. Сақтықпен жалғастырыңыз."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Бөлшек қосу"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> орнына жылжыту"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> орнына қосу"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Орын жарамсыз."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> орны"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Бөлшек қосылды."</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Бөлшек өшірілді."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 4f1136bf001f..e32da00ef6a9 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"បានរក្សាទុកនៅក្នុង <xliff:g id="APP">%1$s</xliff:g> ក្នុងកម្រងព័ត៌មានការងារ"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"បានរក្សាទុកនៅក្នុង <xliff:g id="APP">%1$s</xliff:g> ក្នុងកម្រងព័ត៌មានឯកជន"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ឯកសារ"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> បានរកឃើញ​រូបថតអេក្រង់នេះ។"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> និងកម្មវិធីដែលបើក​ផ្សេងទៀតបានរកឃើញ​រូបថតអេក្រង់នេះ។"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"បិទធាតុ​ក្រាហ្វិកនៅលើអេក្រង់ចាក់សោ"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ប្ដូរ​ធាតុ​ក្រាហ្វិកតាម​បំណង"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ធាតុ​ក្រាហ្វិកនៅលើអេក្រង់ចាក់សោ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ជ្រើសរើសធាតុ​ក្រាហ្វិក"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរ​អ្នក​ប្រើ"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយ​ទាញចុះ"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ផ្កាយរណប ការតភ្ជាប់ខ្សោយ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ផ្កាយរណប មានការតភ្ជាប់ល្អ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ផ្កាយរណប អាចតភ្ជាប់បាន"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ការប្រកាសអាសន្នតាមផ្កាយរណប"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"កម្រងព័ត៌មានការងារ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ល្អសម្រាប់អ្នកប្រើមួយចំនួន តែមិនសម្រាប់គ្រប់គ្នាទេ"</string>
<string name="tuner_warning" msgid="1861736288458481650">"កម្មវិធីសម្រួល UI ប្រព័ន្ធផ្តល់ជូនអ្នកនូវមធ្យោបាយបន្ថែមទៀតដើម្បីកែសម្រួល និងប្តូរចំណុចប្រទាក់អ្នកប្រើ Android តាមបំណង។ លក្ខណៈពិសេសសាកល្បងនេះអាចនឹងផ្លាស់ប្តូរ បំបែក ឬបាត់បង់បន្ទាប់ពីការចេញផ្សាយនាពេលអនាគត។ សូមបន្តដោយប្រុងប្រយ័ត្ន។"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"បញ្ចូល​ប្រអប់"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ផ្លាស់​ទីទៅ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"បញ្ចូលទៅ​ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ទីតាំងគ្មានសុពលភាព។"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"បានបញ្ចូលប្រអប់"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"បាន​ផ្លាស់ទី​ប្រអប់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 71746257500e..e217f8e20470 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ನಲ್ಲಿನ <xliff:g id="APP">%1$s</xliff:g> ನಲ್ಲಿ ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"ಖಾಸಗಿ ಪ್ರೊಫೈಲ್‌ನಲ್ಲಿನ <xliff:g id="APP">%1$s</xliff:g> ನಲ್ಲಿ ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ಫೈಲ್‌ಗಳು"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"ಈ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು <xliff:g id="APPNAME">%1$s</xliff:g> ಪತ್ತೆಹಚ್ಚಿದೆ."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ಹಾಗೂ ತೆರೆದಿರುವ ಇತರ ಆ್ಯಪ್‌ಗಳು ಈ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ಪತ್ತೆಹಚ್ಚಿವೆ."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ವಿಜೆಟ್‌ಗಳನ್ನು ಮುಚ್ಚಿರಿ"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ವಿಜೆಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ವಿಜೆಟ್‌ಗಳು"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ವಿಜೆಟ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ಪುಲ್‌ಡೌನ್ ಮೆನು"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ಅನ್‌ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗು..."</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ಇದರಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತದೆ"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ಕರೆ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ಸಿಸ್ಟಂ UI ಟ್ಯೂನರ್"</string>
<string name="status_bar" msgid="4357390266055077437">"ಸ್ಥಿತಿ ಪಟ್ಟಿ"</string>
<string name="demo_mode" msgid="263484519766901593">"ಸಿಸ್ಟಂ UI ಡೆಮೋ ಮೋಡ್"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ಸ್ಯಾಟಲೈಟ್‌, ಕನೆಕ್ಷನ್ ಕಳಪೆಯಾಗಿದೆ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ಸ್ಯಾಟಲೈಟ್‌, ಕನೆಕ್ಷನ್ ಉತ್ತಮವಾಗಿದೆ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ಸ್ಯಾಟಲೈಟ್, ಕನೆಕ್ಷನ್ ಲಭ್ಯವಿದೆ"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ಸ್ಯಾಟಲೈಟ್ SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ಕೆಲವರಿಗೆ ಮೋಜು ಆಗಿದೆ ಎಲ್ಲರಿಗೆ ಇಲ್ಲ"</string>
<string name="tuner_warning" msgid="1861736288458481650">"ಸಿಸ್ಟಂ UI ಟ್ಯೂನರ್ ನಿಮಗೆ Android ಬಳಕೆದಾರ ಅಂತರಸಂಪರ್ಕವನ್ನು ಸರಿಪಡಿಸಲು ಮತ್ತು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ಹೆಚ್ಚುವರಿ ಮಾರ್ಗಗಳನ್ನು ನೀಡುತ್ತದೆ. ಈ ಪ್ರಾಯೋಗಿಕ ವೈಶಿಷ್ಟ್ಯಗಳು ಭವಿಷ್ಯದ ಬಿಡುಗಡೆಗಳಲ್ಲಿ ಬದಲಾಗಬಹುದು, ವಿರಾಮವಾಗಬಹುದು ಅಥವಾ ಕಾಣಿಸಿಕೊಳ್ಳದಿರಬಹುದು. ಎಚ್ಚರಿಕೆಯಿಂದ ಮುಂದುವರಿಯಿರಿ."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ಟೈಲ್ ಸೇರಿಸಿ"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ಇಲ್ಲಿಗೆ ಸರಿಸಿ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸೇರಿಸಿ"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ಸ್ಥಾನವು ಅಮಾನ್ಯವಾಗಿದೆ."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ಟೈಲ್ ಸೇರಿಸಲಾಗಿದೆ"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ಟೈಲ್ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 55001db97523..3ef3dc862bfb 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"직장 프로필의 <xliff:g id="APP">%1$s</xliff:g>에 저장되었습니다."</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"<xliff:g id="APP">%1$s</xliff:g>의 비공개 프로필에 저장됨"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"파일"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g>에서 이 스크린샷을 감지했습니다."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 및 기타 공개 앱에서 이 스크린샷을 감지했습니다."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"잠금 화면에서 위젯 닫기"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"위젯 맞춤설정"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"잠금 화면의 위젯"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"위젯 선택"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"풀다운 메뉴"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s 음소거 해제"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> 재생 위치:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"오디오 재생 위치:"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"전화 거는 중"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"시스템 UI 튜너"</string>
<string name="status_bar" msgid="4357390266055077437">"상태 표시줄"</string>
<string name="demo_mode" msgid="263484519766901593">"시스템 UI 데모 모드"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"위성, 연결 상태 나쁨"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"위성, 연결 상태 양호"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"위성, 연결 가능"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"위성 긴급 SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"직장 프로필"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"마음에 들지 않을 수도 있음"</string>
<string name="tuner_warning" msgid="1861736288458481650">"시스템 UI 튜너를 사용하면 Android 사용자 인터페이스를 변경 및 맞춤설정할 수 있습니다. 이러한 실험실 기능은 향후 출시 버전에서는 변경되거나 다운되거나 사라질 수 있습니다. 신중하게 진행하시기 바랍니다."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"타일 추가"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> 위치로 이동"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> 위치에 추가"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"위치가 잘못되었습니다."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> 위치"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"타일 추가됨"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"타일 삭제됨"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 7cd68d4e7a86..a75d0d5fe2e7 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Жумуш профилиндеги <xliff:g id="APP">%1$s</xliff:g> колдонмосуна сакталды"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Жеке профилдеги <xliff:g id="APP">%1$s</xliff:g> колдонмосуна сакталды"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ушул скриншотту аныктады."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> жана ачылып турган башка колдонмолор ушул скриншотту аныктады."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Виджеттерди кулпуланган экранда жабуу"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Виджеттерди ыңгайлаштыруу"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Кулпуланган экрандагы виджеттер"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виджет тандоо"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ылдый түшүүчү меню"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s үнүн чыгаруу"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> аркылуу ойнотулууда"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Аудио кайсы жерде ойнотулат:"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Чалууда"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"Абал тилкеси"</string>
<string name="demo_mode" msgid="263484519766901593">"Системанын интерфейсинин демо режими"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Спутник, байланыш начар"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спутник, байланыш жакшы"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Спутник, байланыш бар"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Спутник SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Жумуш профили"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Баарына эле жага бербейт"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner Android колдонуучу интерфейсин жөнгө салып жана ыңгайлаштыруунун кошумча ыкмаларын сунуштайт. Бул сынамык функциялар кийинки чыгарылыштарда өзгөрүлүп, бузулуп же жоголуп кетиши мүмкүн. Абайлап колдонуңуз."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ыкчам баскыч кошуу"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Төмөнкүгө жылдыруу: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>-позицияга кошуу"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Абал жараксыз."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>-позиция"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Карта кошулду"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Карта өчүрүлдү"</string>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index 2769bea141c9..73812c965a17 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -39,7 +39,7 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Title">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">6dp</item>
<item name="android:textSize">36dp</item>
<item name="android:focusable">true</item>
@@ -47,14 +47,14 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Subtitle">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">6dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
<style name="TextAppearance.AuthNonBioCredential.Description">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">6dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index a8751ad0dcb5..eca041e8acf1 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"ບັນທຶກໃນ <xliff:g id="APP">%1$s</xliff:g> ໃນໂປຣໄຟລ໌ບ່ອນເຮັດວຽກແລ້ວ"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"ບັນທຶກໄວ້ໃນ <xliff:g id="APP">%1$s</xliff:g> ໃນໂປຣໄຟລ໌ສ່ວນຕົວແລ້ວ"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ໄຟລ໌"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ກວດພົບຮູບໜ້າຈໍນີ້."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ແລະ ແອັບອື່ນໆທີ່ເປີດຢູ່ກວດພົບຮູບໜ້າຈໍນີ້."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ປິດວິດເຈັດຢູ່ໜ້າຈໍລັອກ"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ປັບແຕ່ງວິດເຈັດ"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ວິດເຈັດຢູ່ໜ້າຈໍລັອກ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ເລືອກວິດເຈັດ"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ເມນູແບບດຶງລົງ"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ເຊົາປິດສຽງ %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"ກຳລັງຫຼິ້ນ <xliff:g id="LABEL">%s</xliff:g> ໃນ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ສຽງຈະຫຼິ້ນຕໍ່ໄປ"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ກຳລັງໂທ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"ແຖບສະຖານະ"</string>
<string name="demo_mode" msgid="263484519766901593">"ໂໝດເດໂມສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ລະບົບ"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ດາວທຽມ, ການເຊື່ອມຕໍ່ບໍ່ດີ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ດາວທຽມ, ການເຊື່ອມຕໍ່ດີ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ດາວທຽມ, ການເຊື່ອມຕໍ່ທີ່ພ້ອມນຳໃຊ້"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS ດາວທຽມ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ມ່ວນຊື່ນສຳລັບບາງຄົນ ແຕ່ບໍ່ແມ່ນສຳລັບທຸກຄົນ"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner ໃຫ້ທ່ານມີວິທີພິເສດຕື່ມອີກໃນການປັບປ່ຽນ ແລະຕົບແຕ່ງສ່ວນຕໍ່ປະສານຜູ້ໃຊ້ຂອງ Android. ຄຸນສົມບັດທົດລອງໃຊ້ເຫຼົ່ານີ້ອາດຈະປ່ຽນແປງ, ຢຸດເຊົາ ຫຼືຫາຍໄປໃນການວາງຈຳໜ່າຍໃນອະນາຄົດ. ຈົ່ງດຳເນີນຕໍ່ດ້ວຍຄວາມລະມັດລະວັງ."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ເພີ່ມແຜ່ນ"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ຍ້າຍໄປ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ຕຳແໜ່ງບໍ່ຖືກຕ້ອງ."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ເພີ່ມແຜ່ນແລ້ວ"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ລຶບແຜ່ນແລ້ວ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index da07fdde552e..fa5790ce8e26 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Išsaugota programoje „<xliff:g id="APP">%1$s</xliff:g>“ darbo profilyje"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Išsaugota „<xliff:g id="APP">%1$s</xliff:g>“ privačiame profilyje"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Failai"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ aptiko šią ekrano kopiją."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ ir kitos atidarytos programos aptiko šią ekrano kopiją."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Uždaryti valdiklius užrakinimo ekrane"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tinkinti valdiklius"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Valdikliai užrakinimo ekrane"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pasirinkite valdiklį"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"išplečiamasis meniu"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"įjungti garsą %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Leidžiama „<xliff:g id="LABEL">%s</xliff:g>“"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Garsas bus leidžiamas"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Skambinama"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sistemos naudotojo sąsajos derinimo priemonė"</string>
<string name="status_bar" msgid="4357390266055077437">"Būsenos juosta"</string>
<string name="demo_mode" msgid="263484519766901593">"Sistemos NS demonstracinis režimas"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Palydovas, prastas ryšys"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Palydovas, geras ryšys"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Palydovas, pasiekiamas ryšys"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Prisijungimas prie palydovo kritiniu atveju"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Darbo profilis"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Smagu, bet ne visada"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Sistemos naudotojo sąsajos derinimo priemonė suteikia papildomų galimybių pagerinti ir tinkinti „Android“ naudotojo sąsają. Šios eksperimentinės funkcijos gali pasikeisti, nutrūkti ar išnykti iš būsimų laidų. Tęskite atsargiai."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pridėti išklotinės elementą"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Perkelkite į <xliff:g id="POSITION">%1$d</xliff:g> poziciją"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridėkite <xliff:g id="POSITION">%1$d</xliff:g> pozicijoje"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Padėtis netinkama."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> pozicija"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Išklotinė pridėta"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Išklotinė pašalinta"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 7e57d8e401c9..9e01526dcb52 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Saglabāts lietotnē <xliff:g id="APP">%1$s</xliff:g> darba profilā"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Saglabāts privātā profilā lietotnē <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Faili"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> konstatēja, ka tika veikts ekrānuzņēmums."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> un citas atvērtas lietotnes konstatēja, ka tika veikts ekrānuzņēmums."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Aizvērt logrīkus bloķēšanas ekrānā"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Pielāgot logrīkus"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Logrīki bloķēšanas ekrānā"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"atlasīt logrīku"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelīts, vājš savienojums"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelīts, labs savienojums"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelīts, ir pieejams savienojums"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelīta SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Darba profils"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Jautri dažiem, bet ne visiem"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Sistēmas saskarnes regulators sniedz papildu veidus, kā mainīt un pielāgot Android lietotāja saskarni. Nākamajās versijās šīs eksperimentālās funkcijas var tikt mainītas, bojātas vai to darbība var tikt pārtraukta. Turpinot esiet uzmanīgs."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pievienot elementu"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pārvietot uz pozīciju numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pievienot elementu pozīcijā numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nederīga pozīcija."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozīcija numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Elements ir pievienots"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Elements ir noņemts"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e1a979e13a10..d1e26e5d8565 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Зачувано во <xliff:g id="APP">%1$s</xliff:g> во работниот профил"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Зачувано во <xliff:g id="APP">%1$s</xliff:g> во приватниот профил"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Датотеки"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ја откри оваа слика од екранот."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> и други отворени апликации ја открија оваа слика од екранот."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Затворете ги виџетите на заклучениот екран"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Приспособете ги виџетите"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Виџети на заклучен екран"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"изберете виџет"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Слаба сателитска врска"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Добра сателитска врска"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Достапна е сателитска врска"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Сателитски SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Работен профил"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за некои, но не за сите"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Адаптерот на УИ на системот ви дава дополнителни начини за дотерување и приспособување на корисничкиот интерфејс на Android. Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додавање плочка"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместување на <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додавање на позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позицијата е погрешна."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Додадена е плочка"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Отстранета е плочка"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 4e0acb003f24..79be0f17fb5a 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"ഔദ്യോഗിക പ്രൊഫൈലിൽ <xliff:g id="APP">%1$s</xliff:g> ആപ്പിൽ സംരക്ഷിച്ചു"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"സ്വകാര്യ പ്രൊഫൈലിൽ <xliff:g id="APP">%1$s</xliff:g> ആപ്പിൽ സംരക്ഷിച്ചു"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ഫയലുകൾ"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ഈ സ്ക്രീൻഷോട്ട് തിരിച്ചറിഞ്ഞു."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്ന ആപ്പും തുറന്നിരിക്കുന്ന മറ്റ് ആപ്പും ഈ സ്ക്രീൻഷോട്ട് തിരിച്ചറിഞ്ഞു."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ലോക്ക് സ്ക്രീനിൽ വിജറ്റുകൾ അടയ്ക്കുക"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ലോക്ക് സ്‌ക്രീനിൽ വിജറ്റുകൾ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"വിജറ്റ് തിരഞ്ഞെടുക്കുക"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"പുൾഡൗൺ മെനു"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s അൺമ്യൂട്ട് ചെയ്യുക"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ഓഡിയോ പ്ലേ ചെയ്യും"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"കോൾ പുരോഗമിക്കുന്നു"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"സിസ്റ്റം UI ട്യൂണർ"</string>
<string name="status_bar" msgid="4357390266055077437">"സ്റ്റാറ്റസ് ബാർ"</string>
<string name="demo_mode" msgid="263484519766901593">"സിസ്റ്റം UI ഡെമോ മോഡ്"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"സാറ്റലൈറ്റ്, മോശം കണക്ഷൻ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"സാറ്റലൈറ്റ്, മികച്ച കണക്ഷൻ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"സാറ്റലൈറ്റ്, കണക്ഷൻ ലഭ്യമാണ്"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"സാറ്റലൈറ്റ് SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ചിലർക്ക് വിനോദം, എന്നാൽ എല്ലാവർക്കുമില്ല"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Android ഉപയോക്തൃ ഇന്റർഫേസ് ആവശ്യമുള്ള രീതിയിൽ മാറ്റുന്നതിനും ഇഷ്ടാനുസൃതമാക്കുന്നതിനും സിസ്റ്റം UI ട്യൂണർ നിങ്ങൾക്ക് അധിക വഴികൾ നൽകുന്നു. ഭാവി റിലീസുകളിൽ ഈ പരീക്ഷണാത്മക ഫീച്ചറുകൾ മാറ്റുകയോ നിർത്തുകയോ അപ്രത്യക്ഷമാവുകയോ ചെയ്തേക്കാം. ശ്രദ്ധയോടെ മുന്നോട്ടുപോകുക."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ടൈൽ ചേർക്കുക"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> എന്നതിലേക്ക് നീക്കുക"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> എന്ന സ്ഥാനത്തേക്ക് ചേർക്കുക"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"സ്ഥാനം അസാധുവാണ്."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ടൈൽ ചേർത്തു"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ടൈൽ നീക്കം ചെയ്‌തു"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 1be3f9219804..93304d64e511 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Ажлын профайл дахь <xliff:g id="APP">%1$s</xliff:g>-д хадгалсан"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Хувийн профайл дахь <xliff:g id="APP">%1$s</xliff:g>-д хадгалсан"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файлс"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> энэ дэлгэцийн агшныг илрүүлсэн."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> болон бусад нээлттэй апп энэ дэлгэцийн агшныг илрүүлсэн."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Түгжээтэй дэлгэц дээр виджетүүдийг хаах"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Виджетийг өөрчлөх"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Түгжээтэй дэлгэц дээрх виджетүүд"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виджет сонгох"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"эвхмэл цэс"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Хиймэл дагуул, холболт муу байна"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Хиймэл дагуул, холболт сайн байна"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Хиймэл дагуул, холболт боломжтой"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Хиймэл дагуул SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Ажлын профайл"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Зарим хүнд хөгжилтэй байж болох ч бүх хүнд тийм биш"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Системийн UI Tохируулагч нь Android хэрэглэгчийн интерфэйсийг тааруулах, өөрчлөх нэмэлт аргыг зааж өгөх болно. Эдгээр туршилтын тохиргоо нь цаашид өөрчлөгдөх, эвдрэх, алга болох магадлалтай. Үйлдлийг болгоомжтой хийнэ үү."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Хавтан нэмэх"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> руу зөөнө үү"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> байрлалд нэмнэ үү"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Байрлал буруу байна."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> байрлал"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Хавтан нэмсэн"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Хавтанг хассан"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index f3ab5b9a9d2a..0aad76430e82 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"<xliff:g id="APP">%1$s</xliff:g> मधील कार्य प्रोफाइलमध्ये सेव्ह केला"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"<xliff:g id="APP">%1$s</xliff:g> मधील खाजगी प्रोफाइलमध्ये सेव्ह केले आहे"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"फाइल"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ने हा स्क्रीनशॉट डिटेक्ट केला."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> आणि उघडलेल्या इतर अ‍ॅप्सनी हा स्क्रीनशॉट डिटेक्ट केला."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"लॉक स्क्रीनवरील विजेट बंद करा"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"विजेट कस्टमाइझ करा"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"लॉक स्क्रीनवरील विजेट"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"विजेट निवडा"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनू"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s अनम्यूट करा"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> वर प्ले करत आहे"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"यावर ऑडिओ प्ले होईल"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"यावर कॉल करत आहे"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"सिस्टम UI ट्युनर"</string>
<string name="status_bar" msgid="4357390266055077437">"स्टेटस बार"</string>
<string name="demo_mode" msgid="263484519766901593">"सिस्टम UI डेमो मोड"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"सॅटेलाइट, खराब कनेक्शन"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"सॅटेलाइट, चांगले कनेक्शन"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"सॅटेलाइट, कनेक्शन उपलब्ध"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"सॅटेलाइट SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाईल"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"सर्वांसाठी नाही तर काहींसाठी मजेदार असू शकते"</string>
<string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनर आपल्‍याला Android यूझर इंटरफेस ट्विक आणि कस्टमाइझ करण्‍याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्‍ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्‍यातील रिलीज मध्‍ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरू ठेवा."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"टाइल जोडा"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> यावर हलवा"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> स्थानावर जोडा"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"स्थान चुकीचे आहे."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थान <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल जोडली"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल काढून टाकली"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index d60ff5ab1bb3..60c028d40869 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Disimpan dalam <xliff:g id="APP">%1$s</xliff:g> dalam profil kerja"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Disimpan dalam <xliff:g id="APP">%1$s</xliff:g> pada profil peribadi"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fail"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> telah mengesan tangkapan skrin ini."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> dan apl lain yang dibuka telah mengesan tangkapan skrin ini."</string>
@@ -237,7 +236,7 @@
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bidai pemberitahuan."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tetapan pantas."</string>
<string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Tetapan pantas dan Bidai pemberitahuan."</string>
- <string name="accessibility_desc_lock_screen" msgid="409034672704273634">"Kunci skrin"</string>
+ <string name="accessibility_desc_lock_screen" msgid="409034672704273634">"Skrin kunci"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Skrin kunci kerja"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"senyap sepenuhnya"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Tutup widget pada skrin kunci"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Sesuaikan widget"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widget pada skrin kunci"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pilih widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu tarik turun"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"nyahredamkan %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Memainkan <xliff:g id="LABEL">%s</xliff:g> pada"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio dimainkan pada"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Membuat panggilan"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Penala UI Sistem"</string>
<string name="status_bar" msgid="4357390266055077437">"Bar status"</string>
<string name="demo_mode" msgid="263484519766901593">"Mod tunjuk cara UI sistem"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, sambungan yang lemah"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, sambungan yang baik"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, sambungan tersedia"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil kerja"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Menarik untuk sesetengah orang tetapi bukan untuk semua"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Penala UI Sistem memberi anda cara tambahan untuk mengolah dan menyesuaikan antara muka Android. Ciri eksperimen ini boleh berubah, rosak atau hilang dalam keluaran masa hadapan. Teruskan dengan berhati-hati."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tambahkan jubin"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Alih ke <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan pada kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Kedudukan tidak sah."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Jubin ditambah"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Jubin dialih keluar"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 42b3602f1a13..dcbf837df5ec 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"အလုပ်ပရိုဖိုင်ရှိ <xliff:g id="APP">%1$s</xliff:g> တွင် သိမ်းထားသည်"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"သီးသန့် ပရိုဖိုင်ရှိ <xliff:g id="APP">%1$s</xliff:g> တွင် သိမ်းထားသည်"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ဖိုင်များ"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> က ဤဖန်သားပြင်ဓာတ်ပုံကို တွေ့ရှိသည်။"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> နှင့် အခြားဖွင့်ထားသော အက်ပ်များက ဤဖန်သားပြင်ဓာတ်ပုံကို တွေ့ရှိသည်။"</string>
@@ -276,7 +275,7 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"သိမ်းထားသည်"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"စသုံးရန်"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"မနက်ဖြန် အလိုအလျောက် ထပ်ဖွင့်ရန်"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"မနက်ဖြန် အလိုအလျောက် ပြန်ဖွင့်ရန်"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"‘အမြန် မျှဝေပါ’ နှင့် Find My Device ကဲ့သို့ တူးလ်များသည် ဘလူးတုသ်သုံးသည်"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"မနက်ဖြန်နံနက်တွင် ဘလူးတုသ် ပွင့်ပါမည်"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"အော်ဒီယို မျှဝေခြင်း"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"လော့ခ်မျက်နှာပြင်ရှိ ဝိဂျက်များကို ပိတ်ရန်"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ဝိဂျက်များကို စိတ်ကြိုက်လုပ်ရန်"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"လော့ခ်မျက်နှာပြင်ရှိ ဝိဂျက်များ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ဝိဂျက် ရွေးရန်"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ဆွဲချမီနူး"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s အသံပြန်ဖွင့်ရန်"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ဖွင့်မည့်နေရာ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"အသံဖွင့်မည့်နေရာ"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ဖုန်းဆက်နေသည်"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"စနစ် UI ဖမ်းစက်"</string>
<string name="status_bar" msgid="4357390266055077437">"အခြေအနေပြနေရာ"</string>
<string name="demo_mode" msgid="263484519766901593">"စနစ် UI စရုပ်ပြမုဒ်"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု မကောင်းပါ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု ကောင်းသည်"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု ရနိုင်သည်"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"အလုပ် ပရိုဖိုင်"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"အချို့သူများ အတွက် ပျော်စရာ ဖြစ်ပေမဲ့ အားလုံး အတွက် မဟုတ်ပါ"</string>
<string name="tuner_warning" msgid="1861736288458481650">"စနစ် UI Tuner က သင့်အတွက် Android အသုံးပြုသူ အင်တာဖေ့စ်ကို ပြောင်းရန်နှင့် စိတ်ကြိုက်ပြုလုပ်ရန် နည်းလမ်း အပိုများကို သင့်အတွက် စီစဉ်ပေးသည်။ အနာဂတ်ဗားရှင်းများတွင် ဤစမ်းသပ်အင်္ဂါရပ်များမှာ ပြောင်းလဲ၊ ပျက်စီး သို့မဟုတ် ပျောက်ကွယ်သွားနိုင်သည်။ သတိဖြင့် ရှေ့ဆက်ပါ။"</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"အကွက်ငယ်ကို ထည့်ရန်"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> သို့ ရွှေ့ရန်"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထားသို့ ပေါင်းထည့်ရန်"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"နေရာ မမှန်ပါ။"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထား"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"အကွက်ငယ်ကို ထည့်ပြီးပါပြီ"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"အကွက်ငယ်ကို ဖယ်ရှားပြီးပါပြီ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index fec8a44880e1..2724a5174752 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Lagret i <xliff:g id="APP">%1$s</xliff:g> i jobbprofilen"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Lagret i <xliff:g id="APP">%1$s</xliff:g> i den private profilen"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Filer"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> har registrert denne skjermdumpen."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og andre åpne apper har registrert denne skjermdumpen."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Lukk moduler på låseskjermen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tilpass moduler"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Moduler på låseskjermen"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"velg modul"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullegardinmeny"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellitt – dårlig tilkobling"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellitt – god tilkobling"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitt – tilkobling tilgjengelig"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-alarm via satellitt"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work-profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Gøy for noen – ikke for alle"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Med System UI Tuner har du flere måter å justere og tilpasse Android-brukergrensesnittet på. Disse eksperimentelle funksjonene kan endres, avbrytes eller fjernes i fremtidige utgivelser. Fortsett med forbehold."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Legg til en infobrikke"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flytt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Legg til posisjonen <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisjonen er ugyldig."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisjon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"En infobrikke er lagt til"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"En infobrikke er fjernet"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 3062263fcc17..1bbab4ae9736 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -175,7 +175,7 @@
<string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"प्याटर्न मिलेन"</string>
<string name="biometric_dialog_wrong_password" msgid="69477929306843790">"पासवर्ड मिलेन"</string>
<string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"अत्यन्तै धेरै पटक गलत प्रयास गरिए। \n <xliff:g id="NUMBER">%d</xliff:g>सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।"</string>
- <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"आपत्कालीन"</string>
+ <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"आपत्‌कालीन"</string>
<string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"फेरि प्रयास गर्नुहोस्। <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> मध्ये <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> प्रयास।"</string>
<string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"तपाईंको डेटा मेटाइने छ"</string>
<string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"तपाईंले अर्को पटक पनि गलत ढाँचा प्रविष्टि गर्नुभयो भने यो डिभाइसको डेटा मेटाइने छ।"</string>
@@ -461,6 +461,10 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"विजेटहरू कस्टमाइज गर्नुहोस्"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"लक स्क्रिनमा भएका विजेटहरू"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"विजेट चयन गर्नुहोस्"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनु"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
@@ -629,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s अनम्युट गर्नुहोस्"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> प्ले गरिँदै छ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"अडियो यसमा प्ले हुने छ"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"कल चलिरहेको छ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"सिस्टम UI ट्युनर"</string>
<string name="status_bar" msgid="4357390266055077437">"स्थिति पट्टी"</string>
<string name="demo_mode" msgid="263484519766901593">"सिस्टम UI को डेमो मोड"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 031fabcc7d63..1a831ac735f2 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Opgeslagen in <xliff:g id="APP">%1$s</xliff:g> in het werkprofiel."</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Opgeslagen in <xliff:g id="APP">%1$s</xliff:g> in het privéprofiel"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Bestanden"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> heeft dit screenshot waargenomen."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> en andere geopende apps hebben dit screenshot waargenomen."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Widgets op het vergrendelscherm sluiten"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Widgets aanpassen"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets op het vergrendelscherm"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"widget selecteren"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pull-downmenu"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"geluid van %s aanzetten"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> wordt afgespeeld op"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio wordt afgespeeld op"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Bellen actief"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Systeem-UI-tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"Statusbalk"</string>
<string name="demo_mode" msgid="263484519766901593">"Demomodus voor systeemgebruikersinterface"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelliet, slechte verbinding"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliet, goede verbinding"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding beschikbaar"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satelliet"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Werkprofiel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Leuk voor sommige gebruikers, maar niet voor iedereen"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Met Systeem-UI-tuner beschikt u over extra manieren om de Android-gebruikersinterface aan te passen. Deze experimentele functies kunnen veranderen, vastlopen of verdwijnen in toekomstige releases. Ga voorzichtig verder."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tegel toevoegen"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Verplaatsen naar <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Toevoegen aan positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positie ongeldig."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tegel toegevoegd"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tegel verwijderd"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index b39be4cf5097..e64b1b47eaa8 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"ୱାର୍କ ପ୍ରୋଫାଇଲରେ ଥିବା <xliff:g id="APP">%1$s</xliff:g>ରେ ସେଭ କରାଯାଇଛି"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"ପ୍ରାଇଭେଟ ପ୍ରୋଫାଇଲରେ ଥିବା <xliff:g id="APP">%1$s</xliff:g>ରେ ସେଭ କରାଯାଇଛି"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ଫାଇଲଗୁଡ଼ିକ"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ଏହି ସ୍କ୍ରିନସଟକୁ ଚିହ୍ନଟ କରିଛି।"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ଏବଂ ଅନ୍ୟ ଓପନ ଆପ୍ସ ଏହି ସ୍କ୍ରିନସଟକୁ ଚିହ୍ନଟ କରିଛି।"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ଲକ ସ୍କ୍ରିନରେ ଥିବା ୱିଜେଟଗୁଡ଼ିକୁ ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ଲକ ସ୍କ୍ରିନରେ ଥିବା ୱିଜେଟଗୁଡ଼ିକ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ୱିଜେଟ ଚୟନ କରନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍‍ ବଦଳାନ୍ତୁ"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ପୁଲଡାଉନ ମେନୁ"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ସାଟେଲାଇଟ, ଦୁର୍ବଳ କନେକ୍ସନ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ସାଟେଲାଇଟ, ଭଲ କନେକ୍ସନ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ସାଟେଲାଇଟ, କନେକ୍ସନ ଉପଲବ୍ଧ"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ସେଟେଲାଇଟ SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"କେତେକଙ୍କ ପାଇଁ ମଜାଦାର, କିନ୍ତୁ ସମସ୍ତଙ୍କ ପାଇଁ ନୁହେଁ"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Android ୟୁଜର୍‍ ଇଣ୍ଟରଫେସ୍‍ ବଦଳାଇବାକୁ ତଥା ନିଜ ପସନ୍ଦ ଅନୁଯାୟୀ କରିବାକୁ ସିଷ୍ଟମ୍‍ UI ଟ୍ୟୁନର୍‍ ଆପଣଙ୍କୁ ଅତିରିକ୍ତ ଉପାୟ ପ୍ରଦାନ କରେ। ଏହି ପରୀକ୍ଷାମୂଳକ ସୁବିଧାମାନ ବଦଳିପାରେ, ଭାଙ୍ଗିପାରେ କିମ୍ବା ଭବିଷ୍ୟତର ରିଲିଜ୍‌ଗୁଡ଼ିକରେ ନଦେଖାଯାଇପାରେ। ସତର୍କତାର ସହ ଆଗକୁ ବଢ଼ନ୍ତୁ।"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>କୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ଅବସ୍ଥିତିରେ ଯୋଗ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ଅବସ୍ଥିତି ଅବୈଧ ଅଟେ।"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ଅବସ୍ଥିତି <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ଟାଇଲ୍ ଯୋଗ କରାଯାଇଛି"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ଟାଇଲ୍ କାଢ଼ି ଦିଆଯାଇଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 5efa1df51f41..394d790ecbdb 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ <xliff:g id="APP">%1$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"<xliff:g id="APP">%1$s</xliff:g> ਦੇ ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ਫ਼ਾਈਲਾਂ"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ਨੂੰ ਇਸ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਪਤਾ ਲੱਗਿਆ ਹੈ।"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ਅਤੇ ਹੋਰ ਖੁੱਲ੍ਹੀਆਂ ਐਪਾਂ ਨੂੰ ਇਸ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਪਤਾ ਲੱਗਿਆ ਹੈ।"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਜੇਟ ਬੰਦ ਕਰੋ"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ਵਿਜੇਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਜੇਟ"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ਵਿਜੇਟ ਚੁਣੋ"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ਪੁੱਲਡਾਊਨ ਮੀਨੂ"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ਸੈਟੇਲਾਈਟ, ਕਨੈਕਸ਼ਨ ਖਰਾਬ ਹੈ"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ਸੈਟੇਲਾਈਟ, ਕਨੈਕਸ਼ਨ ਵਧੀਆ ਹੈ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ਸੈਟੇਲਾਈਟ, ਕਨੈਕਸ਼ਨ ਉਪਲਬਧ ਹੈ"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ਸੈਟੇਲਾਈਟ SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ਕੁਝ ਵਾਸਤੇ ਤਾਂ ਮਜ਼ੇਦਾਰ ਹੈ ਲੇਕਿਨ ਸਾਰਿਆਂ ਵਾਸਤੇ ਨਹੀਂ"</string>
<string name="tuner_warning" msgid="1861736288458481650">"ਸਿਸਟਮ UI ਟਿਊਨਰ ਤੁਹਾਨੂੰ Android ਵਰਤੋਂਕਾਰ ਇੰਟਰਫ਼ੇਸ ਤਬਦੀਲ ਕਰਨ ਅਤੇ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਵਾਧੂ ਤਰੀਕੇ ਦਿੰਦਾ ਹੈ। ਇਹ ਪ੍ਰਯੋਗਾਤਮਿਕ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਭਵਿੱਖ ਦੀ ਰੀਲੀਜ਼ ਵਿੱਚ ਬਦਲ ਸਕਦੀਆਂ ਹਨ, ਟੁੱਟ ਸਕਦੀਆਂ ਹਨ, ਜਾਂ ਅਲੋਪ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਸਾਵਧਾਨੀ ਨਾਲ ਅੱਗੇ ਵੱਧੋ।"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> \'ਤੇ ਲਿਜਾਓ"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ਸਥਾਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ਮੌਜੂਦਾ ਥਾਂ ਅਵੈਧ ਹੈ।"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ਸਥਾਨ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ਟਾਇਲ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ਟਾਇਲ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਗਿਆ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 0aa3140d931e..920862837eb9 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Zapisano w aplikacji <xliff:g id="APP">%1$s</xliff:g> w profilu służbowym"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Zapisano w aplikacji <xliff:g id="APP">%1$s</xliff:g> w profilu prywatnym"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Pliki"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> wykryła ten zrzut ekranu."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> i inne aplikacje wykryły ten zrzut ekranu."</string>
@@ -277,7 +276,7 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"rozłącz"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktywuj"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatycznie włącz ponownie jutro"</string>
- <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcje takie jak szybkie udostępnianie czy Znajdź moje urządzenie korzystają z Bluetootha"</string>
+ <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetootha używają funkcje takie jak szybkie udostępnianie czy Znajdź moje urządzenie"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth włączy się jutro rano"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Udostępnianie dźwięku"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Udostępniam dźwięk"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Zamknij widżety na ekranie blokady"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Dostosuj widżety"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widżety na ekranie blokady"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"wybierz widżet"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelita – połączenie słabe"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelita – połączenie dobre"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelita – połączenie dostępne"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelitarne połączenie alarmowe"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil służbowy"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Dobra zabawa, ale nie dla każdego"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Kalibrator System UI udostępnia dodatkowe sposoby dostrajania i dostosowywania interfejsu Androida. Te eksperymentalne funkcje mogą się zmienić, popsuć lub zniknąć w przyszłych wersjach. Zachowaj ostrożność."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodaj kartę"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Przenieś do pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodaj w pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nieprawidłowa pozycja."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozycja <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Dodano kartę"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Usunięto kartę"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 80e0d22c3cf6..60472c8bcb34 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Salva no app <xliff:g id="APP">%1$s</xliff:g> no perfil de trabalho"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Salva no app <xliff:g id="APP">%1$s</xliff:g> no perfil particular"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"O app <xliff:g id="APPNAME">%1$s</xliff:g> detectou essa captura de tela."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e outros apps abertos detectaram essa captura de tela."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Fechar widgets na tela de bloqueio"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets na tela de bloqueio"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecionar widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string>
@@ -594,7 +596,7 @@
<string name="screen_pinning_exit" msgid="4553787518387346893">"App liberado"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"Ligar"</string>
<string name="stream_system" msgid="7663148785370565134">"Sistema"</string>
- <string name="stream_ring" msgid="7550670036738697526">"Tocar"</string>
+ <string name="stream_ring" msgid="7550670036738697526">"Toques"</string>
<string name="stream_music" msgid="2188224742361847580">"Mídia"</string>
<string name="stream_alarm" msgid="16058075093011694">"Alarme"</string>
<string name="stream_notification" msgid="7930294049046243939">"Notificação"</string>
@@ -630,7 +632,7 @@
<string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string>
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ativar o som de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"O áudio vai tocar em"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string>
<!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
<skip />
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satélite, conexão ruim"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, conexão boa"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string>
<string name="tuner_warning" msgid="1861736288458481650">"O sintonizador System UI fornece maneiras adicionais de ajustar e personalizar a interface do usuário do Android. Esses recursos experimentais podem mudar, falhar ou desaparecer nas versões futuras. Prossiga com cuidado."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar bloco"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloco adicionado"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloco removido"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c21766df6a77..3b9bebb784d8 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Guardada na app <xliff:g id="APP">%1$s</xliff:g> no perfil de trabalho"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Guardada na app <xliff:g id="APP">%1$s</xliff:g> no perfil privado"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ficheiros"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"A app <xliff:g id="APPNAME">%1$s</xliff:g> detetou esta captura de ecrã."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"A app <xliff:g id="APPNAME">%1$s</xliff:g> e outras apps abertas detetaram esta captura de ecrã."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Fechar widgets no ecrã de bloqueio"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets no ecrã de bloqueio"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecionar widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pendente"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"reativar o som de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"A ouvir <xliff:g id="LABEL">%s</xliff:g> em:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio ouvido em:"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chamada em curso"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador da interface do sistema"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de estado"</string>
<string name="demo_mode" msgid="263484519766901593">"Modo de demonstração da IU do sistema"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satélite, ligação fraca"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, boa ligação"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, ligação disponível"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satélite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string>
<string name="tuner_warning" msgid="1861736288458481650">"O Sintonizador da interface do sistema disponibiliza-lhe formas adicionais ajustar e personalizar a interface do utilizador do Android. Estas funcionalidades experimentais podem ser alteradas, deixar de funcionar ou desaparecer em versões futuras. Prossiga com cuidado."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar cartão"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mova para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicione à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Cartão adicionado"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Cartão removido"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 80e0d22c3cf6..60472c8bcb34 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Salva no app <xliff:g id="APP">%1$s</xliff:g> no perfil de trabalho"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Salva no app <xliff:g id="APP">%1$s</xliff:g> no perfil particular"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"O app <xliff:g id="APPNAME">%1$s</xliff:g> detectou essa captura de tela."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e outros apps abertos detectaram essa captura de tela."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Fechar widgets na tela de bloqueio"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets na tela de bloqueio"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecionar widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string>
@@ -594,7 +596,7 @@
<string name="screen_pinning_exit" msgid="4553787518387346893">"App liberado"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"Ligar"</string>
<string name="stream_system" msgid="7663148785370565134">"Sistema"</string>
- <string name="stream_ring" msgid="7550670036738697526">"Tocar"</string>
+ <string name="stream_ring" msgid="7550670036738697526">"Toques"</string>
<string name="stream_music" msgid="2188224742361847580">"Mídia"</string>
<string name="stream_alarm" msgid="16058075093011694">"Alarme"</string>
<string name="stream_notification" msgid="7930294049046243939">"Notificação"</string>
@@ -630,7 +632,7 @@
<string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string>
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ativar o som de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"O áudio vai tocar em"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string>
<!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
<skip />
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satélite, conexão ruim"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, conexão boa"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string>
<string name="tuner_warning" msgid="1861736288458481650">"O sintonizador System UI fornece maneiras adicionais de ajustar e personalizar a interface do usuário do Android. Esses recursos experimentais podem mudar, falhar ou desaparecer nas versões futuras. Prossiga com cuidado."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar bloco"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloco adicionado"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloco removido"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 651f71c4ee9a..84d68e70037c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Salvată în <xliff:g id="APP">%1$s</xliff:g> în profilul de serviciu"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Salvată în <xliff:g id="APP">%1$s</xliff:g> în profilul privat"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fișiere"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> a detectat această captură de ecran."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> și alte aplicații deschise au detectat această captură de ecran."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Închide widgeturile de pe ecranul de blocare"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizează widgeturile"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgeturi pe ecranul de blocare"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selectează un widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Schimbă utilizatorul"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"meniu vertical"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, conexiune slabă"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, conexiune bună"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, conexiune disponibilă"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prin satelit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil de serviciu"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Distractiv pentru unii, dar nu pentru toată lumea"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner oferă modalități suplimentare de a ajusta și a personaliza interfața de utilizare Android. Aceste funcții experimentale pot să se schimbe, să se blocheze sau să dispară din versiunile viitoare. Continuă cu prudență."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adaugă un card"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mută pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adaugă pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Poziție nevalidă."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Cardul a fost adăugat"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Cardul a fost eliminat"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 01109e4c44d8..c405469371da 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Скриншот сохранен в рабочем профиле в приложении <xliff:g id="APP">%1$s</xliff:g>"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Сохранено в приложении \"<xliff:g id="APP">%1$s</xliff:g>\" в личном профиле"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файлы"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Приложение \"<xliff:g id="APPNAME">%1$s</xliff:g>\" обнаружило создание скриншота."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Приложение \"<xliff:g id="APPNAME">%1$s</xliff:g>\" и другие запущенные продукты обнаружили создание скриншота."</string>
@@ -267,7 +266,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не беспокоить"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Нет доступных сопряженных устройств"</string>
- <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Нажмите, чтобы подключить или отключить устройство"</string>
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Нажмите, чтобы подключить или отключить устройство."</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Подключить устройство"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Все"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Использовать"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Закрыть виджеты на заблокированном экране"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Настроить виджеты"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Виджеты на заблокированном экране"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"выбрать виджет"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"раскрывающееся меню"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Спутниковая связь, плохое качество соединения"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спутниковая связь, хорошее качество соединения"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Доступно соединение по спутниковой связи"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Спутниковый SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Рабочий профиль"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Внимание!"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner позволяет настраивать интерфейс устройства Android по вашему вкусу. В будущем эта экспериментальная функция может измениться, перестать работать или исчезнуть."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Добавить панель"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Переместить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Недопустимое расположение."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Панель добавлена"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Панель удалена"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index d59b0b033fa6..37bb23ac64a7 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -461,6 +461,10 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"විජට්ටු අභිරුචි කරන්න"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"අගුළු තිරයෙහි විජට්"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"විජට්ටුව තෝරන්න"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"නිපතන මෙනුව"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 2680d084326c..675a34522086 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Uložená v aplikácii <xliff:g id="APP">%1$s</xliff:g> v pracovnom profile"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Uložené v aplikácii <xliff:g id="APP">%1$s</xliff:g> v súkromnom profile"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikácia <xliff:g id="APPNAME">%1$s</xliff:g> zaznamenala túto snímku obrazovky."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> a ďalšie otvorené aplikácie zaznamenali túto snímku obrazovky."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Zavrieť miniaplikácie na uzamknutej obrazovke"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prispôsobiť miniaplikácie"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Miniaplikácie na uzamknutej obrazovke"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vybrať miniaplikáciu"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbaľovacia ponuka"</string>
@@ -592,7 +594,7 @@
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nie, vďaka"</string>
<string name="screen_pinning_start" msgid="7483998671383371313">"Aplikácia bola pripnutá"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"Aplikácia bola odopnutá"</string>
- <string name="stream_voice_call" msgid="7468348170702375660">"Zavolať"</string>
+ <string name="stream_voice_call" msgid="7468348170702375660">"Hovor"</string>
<string name="stream_system" msgid="7663148785370565134">"Systém"</string>
<string name="stream_ring" msgid="7550670036738697526">"Zvonenie"</string>
<string name="stream_music" msgid="2188224742361847580">"Médiá"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, slabá kvalita pripojenia"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobrá kvalita pripojenia"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, pripojenie je k dispozícii"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Pomoc cez satelit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Pracovný profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Pri používaní tuneru postupujte opatrne"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Tuner používateľského rozhrania systému poskytujte ďalšie spôsoby ladenia a prispôsobenia používateľského rozhrania Android. Tieto experimentálne funkcie sa môžu v budúcich verziách zmeniť, ich poskytovanie môže byť prerušené alebo môžu byť odstránené. Pokračujte opatrne."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pridať kartu"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Presunúť na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridať na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozícia je neplatná."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozícia"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Karta bola pridaná"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Karta bola odstránená"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2e490a840052..f97d6624c00c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Shranjeno v aplikaciji <xliff:g id="APP">%1$s</xliff:g> v delovnem profilu"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Shranjeno v aplikaciji <xliff:g id="APP">%1$s</xliff:g> v zasebnem profilu"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Datoteke"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> je zaznala ta posnetek zaslona."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> in druge odprte aplikacije so zaznale ta posnetek zaslona."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Zapiranje pripomočkov na zaklenjenem zaslonu"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagajanje pripomočkov"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Pripomočki na zaklenjenem zaslonu"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"izberite pripomoček"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satelit, slaba povezava"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra povezava"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, povezava je na voljo"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prek satelita"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Delovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabavno za nekatere, a ne za vse"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Uglaševalnik uporabniškega vmesnika sistema vam omogoča dodatne načine za spreminjanje in prilagajanje uporabniškega vmesnika Android. Te poskusne funkcije lahko v prihodnjih izdajah kadar koli izginejo, se spremenijo ali pokvarijo. Bodite previdni."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodajanje ploščice"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premik na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Položaj je neveljaven."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ploščica je bila dodana"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ploščica je bila odstranjena"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 5e15bf0e3e62..b638198c6d5f 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Ruajtur në <xliff:g id="APP">%1$s</xliff:g> në profilin e punës"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Ruajtur në <xliff:g id="APP">%1$s</xliff:g> në profilin privat"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Skedarë"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> zbuloi këtë pamje ekrani."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> dhe aplikacionet e tjera të hapura zbuluan këtë pamje ekrani."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Mbyll miniaplikacionet në ekranin e kyçjes"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizo miniaplikacionet"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Miniaplikacionet në ekranin e kyçjes"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"zgjidh miniaplikacionin"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Sateliti. Lidhje e dobët"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Sateliti. Lidhje e mirë"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sateliti. Ofrohet lidhje"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satelitor"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profili i punës"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Argëtim për disa, por jo për të gjithë!"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit të jep mënyra shtesë për të tërhequr dhe personalizuar ndërfaqen Android të përdoruesit. Këto funksione eksperimentale mund të ndryshojnë, prishen ose zhduken në versionet e ardhshme. Vazhdo me kujdes."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Shto pllakëzën"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Zhvendos te <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Shto te pozicioni <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozicion i pavlefshëm."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Pllakëza u shtua"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Pllakëza u hoq"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 8fa9fc3eb915..4cc1134a369a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Сачувано је у апликацији <xliff:g id="APP">%1$s</xliff:g> на пословном профилу"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Сачувано је у апликацији <xliff:g id="APP">%1$s</xliff:g> на приватном профилу"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Фајлови"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Апликација <xliff:g id="APPNAME">%1$s</xliff:g> је открила овај снимак екрана."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> и друге отворене апликације су откриле овај снимак екрана."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Затворите виџете на закључаном екрану"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Прилагодите виџете"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Виџети на закључаном екрану"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"изаберите виџет"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падајући мени"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Сателит, веза је лоша"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Сателит, веза је добра"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Сателит, веза је доступна"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Хитна помоћ преко сателита"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Пословни профил"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за неке, али не за све"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Тјунер за кориснички интерфејс система вам пружа додатне начине за подешавање и прилагођавање Android корисничког интерфејса. Ове експерименталне функције могу да се промене, откажу или нестану у будућим издањима. Будите опрезни."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додајте плочицу"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместите на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додајте на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позиција је неважећа."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Плочица је додата"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Плочица је уклоњена"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c3b6f1ecb8d0..b0ce12f8e5a2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Sparad i <xliff:g id="APP">%1$s</xliff:g> i jobbprofilen"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Sparad i <xliff:g id="APP">%1$s</xliff:g> i den privata profilen"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Filer"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> identifierade skärmbilden."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> och andra öppna appar identifierade skärmbilden."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Stäng widgetar på låsskärmen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Anpassa widgetar"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgetar på låsskärmen"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"välj widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellit, dålig anslutning"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit, bra anslutning"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, anslutning tillgänglig"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-larm via satellit"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Jobbprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Kul för vissa, inte för alla"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Du kan använda inställningarna för systemgränssnitt för att justera användargränssnittet i Android. Dessa experimentfunktioner kan när som helst ändras, sluta fungera eller försvinna. Använd med försiktighet."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lägg till ruta"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flytta till <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lägg till på position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positionen är ogiltig."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kortet har lagts till"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kortet har tagits bort"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index ffcf35624d7e..8dc22a785069 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Imehifadhiwa kwenye <xliff:g id="APP">%1$s</xliff:g> katika wasifu wa kazini"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Imehifadhiwa kwenye <xliff:g id="APP">%1$s</xliff:g> katika wasifu binafsi"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Faili"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> imetambua picha hii ya skrini."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> na zingine zinazotumika zimetambua picha hii ya skrini."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Funga wijeti kwenye skrini iliyofungwa"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Badilisha wijeti upendavyo"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Wijeti kwenye skrini iliyofungwa"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"chagua wijeti"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Setilaiti, muunganisho hafifu"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Setilaiti, muunganisho thabiti"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Setilaiti, muunganisho unapatikana"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Msaada kupitia Setilaiti"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Wasifu wa kazini"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Kinafurahisha kwa baadhi ya watu lakini si wote"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Kirekebishi cha kiolesura cha mfumo kinakupa njia zaidi za kugeuza na kubadilisha kiolesura cha Android ili kikufae. Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ongeza kigae"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Hamishia kwenye <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ongeza kwenye nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nafasi si sahihi."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kigae kimewekwa"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kigae kimeondolewa"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/styles.xml b/packages/SystemUI/res/values-sw600dp-land/styles.xml
index 0d46cbcf050e..cde1a1373bed 100644
--- a/packages/SystemUI/res/values-sw600dp-land/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/styles.xml
@@ -18,7 +18,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<style name="TextAppearance.AuthNonBioCredential.Title">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:textSize">36sp</item>
<item name="android:focusable">true</item>
@@ -26,14 +26,14 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Subtitle">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
<style name="TextAppearance.AuthNonBioCredential.Description">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
diff --git a/packages/SystemUI/res/values-sw600dp-port/styles.xml b/packages/SystemUI/res/values-sw600dp-port/styles.xml
index 3add566e439c..85e7af6ee1de 100644
--- a/packages/SystemUI/res/values-sw600dp-port/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/styles.xml
@@ -26,7 +26,7 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Title">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">24dp</item>
<item name="android:textSize">36sp</item>
<item name="android:focusable">true</item>
diff --git a/packages/SystemUI/res/values-sw720dp-land/styles.xml b/packages/SystemUI/res/values-sw720dp-land/styles.xml
index 7cdd07bec443..e75173d152b0 100644
--- a/packages/SystemUI/res/values-sw720dp-land/styles.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/styles.xml
@@ -18,7 +18,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<style name="TextAppearance.AuthNonBioCredential.Title">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:textSize">36sp</item>
<item name="android:focusable">true</item>
@@ -26,14 +26,14 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Subtitle">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
<style name="TextAppearance.AuthNonBioCredential.Description">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
diff --git a/packages/SystemUI/res/values-sw720dp-port/styles.xml b/packages/SystemUI/res/values-sw720dp-port/styles.xml
index 3add566e439c..85e7af6ee1de 100644
--- a/packages/SystemUI/res/values-sw720dp-port/styles.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/styles.xml
@@ -26,7 +26,7 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Title">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">24dp</item>
<item name="android:textSize">36sp</item>
<item name="android:focusable">true</item>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index e19f66ef492f..ee86acac2d7e 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"பணிக் கணக்கில் உள்ள <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸில் சேமிக்கப்பட்டது"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"தனிப்பட்ட சுயவிவரத்தில் உள்ள <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸில் சேமிக்கப்பட்டது"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"இந்த ஸ்கிரீன்ஷாட்டை <xliff:g id="APPNAME">%1$s</xliff:g> கண்டறிந்துள்ளது."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"இந்த ஸ்கிரீன்ஷாட்டை <xliff:g id="APPNAME">%1$s</xliff:g> மற்றும் திறந்திருக்கும் பிற ஆப்ஸ் கண்டறிந்துள்ளன."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"பூட்டுத் திரையில் விட்ஜெட்களை மூடும்"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"விட்ஜெட்களைப் பிரத்தியேகமாக்கும்"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"பூட்டுத் திரையில் விட்ஜெட்கள்"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"விட்ஜெட்டைத் தேர்ந்தெடுக்கும்"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"கீழ் இழுக்கும் மெனு"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"சாட்டிலைட், மோசமான இணைப்பு"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"சாட்டிலைட், நிலையான இணைப்பு"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"சாட்டிலைட், இணைப்பு கிடைக்கிறது"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"சாட்டிலைட் SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"பணிக் கணக்கு"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"சில வேடிக்கையாக இருந்தாலும் கவனம் தேவை"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner, Android பயனர் இடைமுகத்தை மாற்றவும் தனிப்பயனாக்கவும் கூடுதல் வழிகளை வழங்குகிறது. இந்தப் பரிசோதனைக்குரிய அம்சங்கள் எதிர்கால வெளியீடுகளில் மாற்றப்படலாம், இடைநிறுத்தப்படலாம் அல்லது தோன்றாமல் போகலாம். கவனத்துடன் தொடரவும்."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"கட்டத்தைச் சேர்"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>க்கு நகர்த்தும்"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>ல் சேர்க்கும்"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"நிலை தவறானது."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"இடம்: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"கட்டம் சேர்க்கப்பட்டது"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"கட்டம் அகற்றப்பட்டது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 0d079bf01489..d8622a3d9fc1 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"వర్క్ ప్రొఫైల్‌లోని <xliff:g id="APP">%1$s</xliff:g>‌లో సేవ్ చేయబడింది"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"ప్రైవేట్ ప్రొఫైల్‌లోని <xliff:g id="APP">%1$s</xliff:g>‌లో సేవ్ చేయబడింది"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ఫైల్స్"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g>, ఈ స్క్రీన్‌షాట్‌ను గుర్తించింది."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g>, ఇతర ఓపెన్ యాప్‌లు ఈ స్క్రీన్‌షాట్‌ను గుర్తించాయి."</string>
@@ -273,7 +272,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"బ్లూటూత్ వాడండి"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"కనెక్ట్ అయింది"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ఆడియో షేరింగ్"</string>
- <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"సేవ్ చేయబడింది"</string>
+ <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"సేవ్ అయ్యింది"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"డిస్‌కనెక్ట్ చేయండి"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"యాక్టివేట్ చేయండి"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"రేపు మళ్లీ ఆటోమేటిక్‌గా ఆన్ చేస్తుంది"</string>
@@ -370,7 +369,7 @@
<string name="quick_settings_contrast_medium" msgid="5158352575583902566">"మధ్యస్థం"</string>
<string name="quick_settings_contrast_high" msgid="656049259587494499">"అధికం"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"వినికిడి పరికరాలు"</string>
- <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"వినికిడి పరికరం"</string>
+ <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"వినికిడి పరికరాలు"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"కొత్త పరికరాన్ని పెయిర్ చేయడానికి క్లిక్ చేయండి"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ప్రీసెట్‌ను అప్‌డేట్ చేయడం సాధ్యపడలేదు"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"లాక్ స్క్రీన్‌లో విడ్జెట్‌లను మూసివేయండి"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"విడ్జెట్‌లను అనుకూలంగా మార్చండి"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"లాక్ స్క్రీన్‌లో విడ్జెట్‌లు"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"విడ్జెట్‌ను ఎంచుకోండి"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"పుల్‌డౌన్ మెనూ"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"శాటిలైట్, కనెక్షన్ సరిగా లేదు"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"శాటిలైట్, కనెక్షన్ బాగుంది"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"శాటిలైట్, కనెక్షన్ అందుబాటులో ఉంది"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ఎమర్జెన్సీ శాటిలైట్ సహాయం"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ఆఫీస్ ప్రొఫైల్‌"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"కొందరికి సరదాగా ఉంటుంది కానీ అందరికీ అలాగే ఉండదు"</string>
<string name="tuner_warning" msgid="1861736288458481650">"సిస్టమ్ UI ట్యూనర్ Android వినియోగదారు ఇంటర్‌ఫేస్‌ను మెరుగుపరచడానికి మరియు అనుకూలంగా మార్చడానికి మీకు మరిన్ని మార్గాలను అందిస్తుంది. ఈ ప్రయోగాత్మక లక్షణాలు భవిష్యత్తు విడుదలల్లో మార్పుకు లోనవ్వచ్చు, తాత్కాలికంగా లేదా పూర్తిగా నిలిపివేయవచ్చు. జాగ్రత్తగా కొనసాగండి."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"టైల్‌ను జోడించండి"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>కు తరలించండి"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> స్థానానికి జోడించండి"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ప్రస్తుత పొజిషన్ చెల్లదు."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"టైల్ జోడించబడింది"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"టైల్ తీసివేయబడింది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 7063592e1ec3..9f09b9ccdfe4 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"บันทึกไว้ที่ <xliff:g id="APP">%1$s</xliff:g> ในโปรไฟล์งาน"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"บันทึกไว้ที่ <xliff:g id="APP">%1$s</xliff:g> ในโปรไฟล์ส่วนตัว"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ไฟล์"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ตรวจพบภาพหน้าจอนี้"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> และแอปอื่นๆ ที่เปิดอยู่ตรวจพบภาพหน้าจอนี้"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"ปิดวิดเจ็ตในหน้าจอล็อก"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ปรับแต่งวิดเจ็ต"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"วิดเจ็ตในหน้าจอล็อก"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"เลือกวิดเจ็ต"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"เมนูแบบเลื่อนลง"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"เปิดเสียง%s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"กำลังเล่น <xliff:g id="LABEL">%s</xliff:g> ใน"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"เสียงจะเล่นต่อใน"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"กำลังโทรติดต่อ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ตัวรับสัญญาณ UI ระบบ"</string>
<string name="status_bar" msgid="4357390266055077437">"แถบสถานะ"</string>
<string name="demo_mode" msgid="263484519766901593">"โหมดสาธิต UI ของระบบ"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ดาวเทียม, การเชื่อมต่อไม่ดี"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ดาวเทียม, การเชื่อมต่อดี"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ดาวเทียม, การเชื่อมต่อที่พร้อมใช้งาน"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS ดาวเทียม"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"โปรไฟล์งาน"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"เพลิดเพลินกับบางส่วนแต่ไม่ใช่ทั้งหมด"</string>
<string name="tuner_warning" msgid="1861736288458481650">"ตัวรับสัญญาณ UI ระบบช่วยให้คุณมีวิธีพิเศษในการปรับแต่งและกำหนดค่าส่วนติดต่อผู้ใช้ Android ฟีเจอร์รุ่นทดลองเหล่านี้อาจมีการเปลี่ยนแปลง ขัดข้อง หรือหายไปในเวอร์ชันอนาคต โปรดดำเนินการด้วยความระมัดระวัง"</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"เพิ่มชิ้นส่วน"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ย้ายไปที่ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"เพิ่มไปยังตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ตำแหน่งไม่ถูกต้อง"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"เพิ่มชิ้นส่วนแล้ว"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"นำชิ้นส่วนออกแล้ว"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index fe188140df06..9122627107f4 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Na-save sa <xliff:g id="APP">%1$s</xliff:g> sa profile sa trabaho"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Naka-save sa <xliff:g id="APP">%1$s</xliff:g> sa pribadong profile"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Mga File"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Na-detect ng <xliff:g id="APPNAME">%1$s</xliff:g> ang screenshot. na ito"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Na-detect ng <xliff:g id="APPNAME">%1$s</xliff:g> at ng iba pang bukas na app ang screenshot na ito."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Isara ang mga widget sa lock screen"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"I-customize ang mga widget"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Mga widget sa lock screen"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pumili ng widget"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"i-unmute ang %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Nagpe-play ang <xliff:g id="LABEL">%s</xliff:g> sa"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"I-play ang audio sa"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Tumatawag sa"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Tuner ng System UI"</string>
<string name="status_bar" msgid="4357390266055077437">"Status bar"</string>
<string name="demo_mode" msgid="263484519766901593">"Demo mode ng System UI"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Satellite, mahina ang koneksyon"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, malakas ang koneksyon"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, may koneksyon"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profile sa trabaho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Masaya para sa ilan ngunit hindi para sa lahat"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Nagbibigay sa iyo ang Tuner ng System UI ng mga karagdagang paraan upang baguhin at i-customize ang user interface ng Android. Ang mga pang-eksperimentong feature na ito ay maaaring magbago, masira o mawala sa mga pagpapalabas sa hinaharap. Magpatuloy nang may pag-iingat."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Magdagdag ng tile"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Ilipat sa <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Idagdag sa posisyong <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Invalid ang posisyon."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Idinagdag ang tile"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Inalis ang tile"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e0ea27d86395..1f7a8e0b4ca4 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"İş profilinde <xliff:g id="APP">%1$s</xliff:g> uygulamasına kaydedildi"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Gizli profilde <xliff:g id="APP">%1$s</xliff:g> uygulamasına kaydedildi"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Dosyalar"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> bu ekran görüntüsünü algıladı."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ve diğer açık uygulamalar bu ekran görüntüsünü algıladı."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Kilit ekranındaki widget\'ları kapat"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Widget\'ları özelleştir"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Kilit ekranındaki widget\'lar"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"widget seçin"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string>
@@ -594,14 +596,14 @@
<string name="screen_pinning_exit" msgid="4553787518387346893">"Uygulamanın sabitlemesi kaldırıldı"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"Çağrı"</string>
<string name="stream_system" msgid="7663148785370565134">"Sistem"</string>
- <string name="stream_ring" msgid="7550670036738697526">"Zili çaldır"</string>
+ <string name="stream_ring" msgid="7550670036738697526">"Zil"</string>
<string name="stream_music" msgid="2188224742361847580">"Medya"</string>
<string name="stream_alarm" msgid="16058075093011694">"Alarm"</string>
<string name="stream_notification" msgid="7930294049046243939">"Bildirim"</string>
<string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string>
<string name="stream_dtmf" msgid="7322536356554673067">"Çift ton çoklu frekans"</string>
<string name="stream_accessibility" msgid="3873610336741987152">"Erişilebilirlik"</string>
- <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zili çaldır"</string>
+ <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zil"</string>
<string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Titreşim"</string>
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Sesi kapat"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Yayınla"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Uydu, bağlantı zayıf"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Uydu, bağlantı güçlü"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Uydu, bağlantı mevcut"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Acil Uydu Bağlantısı"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"İş profili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Bazıları için eğlenceliyken diğerleri için olmayabilir"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Sistem Kullanıcı Arayüzü Ayarlayıcı, Android kullanıcı arayüzünde değişiklikler yapmanız ve arayüzü özelleştirmeniz için ekstra yollar sağlar. Bu deneysel özellikler değişebilir, bozulabilir veya gelecekteki sürümlerde yer almayabilir. Dikkatli bir şekilde devam edin."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Kutu ekle"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna taşı"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna ekle"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Konum geçersiz."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Konum: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kutu eklendi"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kutu kaldırıldı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index d479eb968851..e9b45bf14e99 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Збережено в додатку <xliff:g id="APP">%1$s</xliff:g> у робочому профілі"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Збережено в додатку <xliff:g id="APP">%1$s</xliff:g> в особистому профілі"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файли"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"Додаток <xliff:g id="APPNAME">%1$s</xliff:g> виявив цей знімок екрана."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> та інші відкриті додатки виявили цей знімок екрана."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Закрити віджети на заблокованому екрані"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Налаштувати віджети"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Віджети на заблокованому екрані"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виберіть віджет"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Погане з’єднання із супутником"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Хороше з’єднання із супутником"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Доступне з’єднання із супутником"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Супутниковий сигнал SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Робочий профіль"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Це цікаво, але будьте обачні"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner пропонує нові способи налаштувати та персоналізувати інтерфейс користувача Android. Ці експериментальні функції можуть змінюватися, не працювати чи зникати в майбутніх версіях. Будьте обачні."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додати панель"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Перемістити на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додати на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позиція недійсна."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Опцію додано"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Опцію вилучено"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3bf6134d56b1..f9fc9f0de389 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"دفتری پروفائل میں <xliff:g id="APP">%1$s</xliff:g> میں محفوظ کی گئی"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"نجی پروفائل میں <xliff:g id="APP">%1$s</xliff:g> میں محفوظ کیا گیا"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"فائلز"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"‫<xliff:g id="APPNAME">%1$s</xliff:g> نے اس اسکرین شاٹ کا پتا لگایا۔"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"‫<xliff:g id="APPNAME">%1$s</xliff:g> اور دیگر کھلی ایپس نے اس اسکرین شاٹ کا پتا لگایا۔"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"مقفل اسکرین پر ویجٹس بند کریں"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ویجیٹس کو حسب ضرورت بنائیں"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"مقفل اسکرین پر ویجیٹس"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ویجیٹ منتخب کریں"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"پل ڈاؤن مینیو"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"سیٹلائٹ، کنکشن خراب ہے"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"سیٹلائٹ، کنکشن اچھا ہے"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"سیٹلائٹ، کنکشن دستیاب ہے"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"‏سیٹلائٹ SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"دفتری پروفائل"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"کچھ کیلئے دلچسپ لیکن سبھی کیلئے نہیں"</string>
<string name="tuner_warning" msgid="1861736288458481650">"‏سسٹم UI ٹیونر Android صارف انٹر فیس میں ردوبدل کرنے اور اسے حسب ضرورت بنانے کیلئے آپ کو اضافی طریقے دیتا ہے۔ یہ تجرباتی خصوصیات مستقبل کی ریلیزز میں تبدیل ہو سکتی، رک سکتی یا غائب ہو سکتی ہیں۔ احتیاط کے ساتھ آگے بڑھیں۔"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ٹائل شامل کریں"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> میں منتقل کریں"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g> میں شامل کریں"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"پوزیشن غلط ہے۔"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ٹائل کو شامل کیا گیا"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ٹائل کو ہٹا دیا گیا"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 73bd409eb27c..60baeec4ed84 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"Ish profilidagi <xliff:g id="APP">%1$s</xliff:g> ilovasiga saqlandi"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Yopiq profildagi <xliff:g id="APP">%1$s</xliff:g> ilovasiga saqlandi"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fayllar"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> skrinshot olinganini aniqladi."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> va boshqa ochiq ilovalar skrinshot olinganini aniqladi."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Ekran qulfida vidjetlarni yopish"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Vidjetlarni moslash"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Ekran qulfidagi vidjetlar"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vidjet tanlash"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"tortib tushiriladigan menyu"</string>
@@ -631,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ovozini chiqarish"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>da ijro etilmoqda"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio ijro etiladi"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chaqiruv yoniq"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"SystemUI Tuner"</string>
<string name="status_bar" msgid="4357390266055077437">"Holat qatori"</string>
<string name="demo_mode" msgid="263484519766901593">"Tizim interfeysi demo rejimi"</string>
@@ -660,8 +661,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Sputnik, aloqa sifati past"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Sputnik, aloqa sifati yaxshi"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sputnik, aloqa mavjud"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Sputnik SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Ish profili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diqqat!"</string>
<string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner yordamida siz Android foydalanuvchi interfeysini tuzatish va o‘zingizga moslashtirishingiz mumkin. Ushbu tajribaviy funksiyalar o‘zgarishi, buzilishi yoki keyingi versiyalarda olib tashlanishi mumkin. Ehtiyot bo‘lib davom eting."</string>
@@ -866,8 +866,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Katakcha kiritish"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Bu joyga olish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bu joyga kiritish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozitsiya yaroqsiz."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Katakcha kiritildi"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Katakcha olib tashlandi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index fb4cd135b63d..9656eb3cf81e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -97,8 +97,7 @@
<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>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Đã lưu vào <xliff:g id="APP">%1$s</xliff:g> trong hồ sơ công việc"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Đã lưu vào <xliff:g id="APP">%1$s</xliff:g> trong hồ sơ riêng tư"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> đã phát hiện thấy ảnh chụp màn hình này."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> và các ứng dụng đang mở khác đã phát hiện thấy ảnh chụp màn hình này."</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Đóng các tiện ích trên màn hình khoá"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tuỳ chỉnh tiện ích"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Các tiện ích trên màn hình khoá"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"chọn tiện ích"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Kết nối vệ tinh kém"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Kết nối vệ tinh tốt"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Hiện có kết nối vệ tinh"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Liên lạc khẩn cấp qua vệ tinh"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Hồ sơ công việc"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Thú vị đối với một số người nhưng không phải tất cả"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Bộ điều hướng giao diện người dùng hệ thống cung cấp thêm cho bạn những cách chỉnh sửa và tùy chỉnh giao diện người dùng Android. Những tính năng thử nghiệm này có thể thay đổi, hỏng hoặc biến mất trong các phiên bản tương lai. Hãy thận trọng khi tiếp tục."</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Thêm ô"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Di chuyển tới <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Thêm vào vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Vị trí không hợp lệ."</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Đã thêm thẻ thông tin"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Đã xóa thẻ thông tin"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 47de3ea6d5de..6f1a0bd0bc7b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"已保存到工作资料名下的 <xliff:g id="APP">%1$s</xliff:g>中"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"已保存在私密个人资料中的<xliff:g id="APP">%1$s</xliff:g>内"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"文件"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> 检测到此屏幕截图。"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 及其他打开的应用检测到此屏幕截图。"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"关闭锁定屏幕上的微件"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"自定义微件"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"锁定屏幕上的微件"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"选择微件"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉菜单"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"卫星,连接质量不佳"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"卫星,连接质量良好"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"卫星,可连接"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"卫星紧急呼救"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"工作资料"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"并不适合所有用户"</string>
<string name="tuner_warning" msgid="1861736288458481650">"系统界面调节工具可让您以更多方式调整及定制 Android 界面。在日后推出的版本中,这些实验性功能可能会变更、失效或消失。操作时请务必谨慎。"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"添加功能块"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移至 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"添加到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置无效。"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已添加功能块"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除功能块"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 491ec4d98889..47d0692c3d84 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"已儲存在工作設定檔的「<xliff:g id="APP">%1$s</xliff:g>」中"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"已儲存在私人設定檔的「<xliff:g id="APP">%1$s</xliff:g>」中"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"檔案"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> 偵測到此螢幕截圖。"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 和其他開啟的應用程式偵測到此螢幕截圖。"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"關閉上鎖畫面上的小工具"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"自訂小工具"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"上鎖畫面上的小工具"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"揀小工具"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"衛星,連線質素唔好"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛星,連線質素好"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可以連線"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連接"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"工作設定檔"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"這只是測試版本,並不包含完整功能"</string>
<string name="tuner_warning" msgid="1861736288458481650">"使用者介面調諧器讓你以更多方法修改和自訂 Android 使用者介面。但請小心,這些實驗功能可能會在日後發佈時更改、分拆或消失。"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"加圖塊"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移去 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"加去位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置冇效。"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"加咗圖塊"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"移除咗圖塊"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index f60b392d1f64..b3ed7a051bc0 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -97,8 +97,7 @@
<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="203041724052970693">"已儲存在工作資料夾的「<xliff:g id="APP">%1$s</xliff:g>」中"</string>
- <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) -->
- <skip />
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"已儲存在個人資料夾的「<xliff:g id="APP">%1$s</xliff:g>」"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"檔案"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"「<xliff:g id="APPNAME">%1$s</xliff:g>」偵測到這張螢幕截圖。"</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"「<xliff:g id="APPNAME">%1$s</xliff:g>」和其他開啟的應用程式偵測到這張螢幕截圖。"</string>
@@ -461,7 +460,10 @@
<string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"關閉螢幕鎖定畫面上的小工具"</string>
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"自訂小工具"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"螢幕鎖定畫面上的小工具"</string>
- <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) -->
+ <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"選取小工具"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
<skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string>
@@ -660,8 +662,7 @@
<string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"衛星,連線品質不佳"</string>
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛星,連線品質良好"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可連線"</string>
- <!-- no translation found for satellite_connected_carrier_text (118524195198532589) -->
- <skip />
+ <string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連線"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"工作資料夾"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"有趣與否,見仁見智"</string>
<string name="tuner_warning" msgid="1861736288458481650">"系統使用者介面調整精靈可讓你透過其他方式,調整及自訂 Android 使用者介面。這些實驗性功能隨著版本更新可能會變更、損壞或消失,執行時請務必謹慎。"</string>
@@ -866,8 +867,7 @@
<string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"新增圖塊"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移至 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"新增到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) -->
- <skip />
+ <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置無效。"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已新增設定方塊"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除設定方塊"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d40f2c17d802..6e9e08b63095 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -461,6 +461,10 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Yenza ngokwezifiso amawijethi"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Amawijethi ekukhiyeni isikrini"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"khetha iwijethi"</string>
+ <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
+ <skip />
+ <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
+ <skip />
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"imenyu yokudonsela phansi"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wonke ama-app nedatha kulesi sikhathi azosuswa."</string>
@@ -629,8 +633,7 @@
<string name="volume_panel_hint_unmute" msgid="7489063242934477382">"susa ukuthula kwe-%s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Idlala ku-<xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Umsindo uzodlala"</string>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ifonela kokuthi"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Isishuni se-UI yesistimu"</string>
<string name="status_bar" msgid="4357390266055077437">"Ibha yesimo"</string>
<string name="demo_mode" msgid="263484519766901593">"Imodi yedemo ye-UI yesistimu"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6bfd0887c404..2ba72e386cd1 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -635,9 +635,13 @@
58.0001 29.2229,56.9551 26.8945,55.195
</string>
- <!-- The time (in ms) needed to trigger the lock icon view's long-press affordance -->
+ <!-- The time (in ms) needed to trigger the device entry icon view's long-press affordance -->
<integer name="config_lockIconLongPress" translatable="false">200</integer>
+ <!-- The time (in ms) needed to trigger the device entry icon view's long-press affordance
+ when the device supports an under-display fingerprint sensor -->
+ <integer name="config_udfpsDeviceEntryIconLongPress" translatable="false">100</integer>
+
<!-- package name of a built-in camera app to use to restrict implicit intent resolution
when the double-press power gesture is used. Ignored if empty. -->
<string translatable="false" name="config_cameraGesturePackage"></string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a7a6d5b2f305..a1daebd7513e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -430,6 +430,7 @@
<dimen name="overlay_button_corner_radius">16dp</dimen>
<!-- Margin between successive chips -->
<dimen name="overlay_action_chip_margin_start">8dp</dimen>
+ <dimen name="shelf_action_chip_margin_start">12dp</dimen>
<dimen name="overlay_action_chip_padding_vertical">12dp</dimen>
<dimen name="overlay_action_chip_icon_size">24sp</dimen>
<!-- Padding on each side of the icon for icon-only chips -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 69de45ea1acf..2c4cdb9ee796 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -175,21 +175,21 @@
</style>
<style name="TextAppearance.AuthCredential.OldTitle">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:paddingTop">12dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">24sp</item>
</style>
<style name="TextAppearance.AuthCredential.OldSubtitle">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">16sp</item>
</style>
<style name="TextAppearance.AuthCredential.OldDescription">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">14sp</item>
@@ -205,7 +205,7 @@
</style>
<style name="TextAppearance.AuthCredential.Title" parent="TextAppearance.Material3.HeadlineSmall" >
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
@@ -257,7 +257,7 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Title">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">24dp</item>
<item name="android:textSize">36dp</item>
<item name="android:focusable">true</item>
@@ -265,14 +265,14 @@
</style>
<style name="TextAppearance.AuthNonBioCredential.Subtitle">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">20dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
<style name="TextAppearance.AuthNonBioCredential.Description">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:layout_marginTop">20dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index c08b0837da8e..69aa90996946 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -77,7 +77,7 @@ public class QuickStepContract {
// settings is expanded.
public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11;
// Winscope tracing is enabled
- public static final int SYSUI_STATE_TRACING_ENABLED = 1 << 12;
+ public static final int SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION = 1 << 12;
// The Assistant gesture should be constrained. It is up to the launcher implementation to
// decide how to constrain it
public static final int SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1 << 13;
@@ -148,7 +148,7 @@ public class QuickStepContract {
SYSUI_STATE_OVERVIEW_DISABLED,
SYSUI_STATE_HOME_DISABLED,
SYSUI_STATE_SEARCH_DISABLED,
- SYSUI_STATE_TRACING_ENABLED,
+ SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION,
SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
SYSUI_STATE_BUBBLES_EXPANDED,
SYSUI_STATE_DIALOG_SHOWING,
@@ -211,8 +211,8 @@ public class QuickStepContract {
if ((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0) {
str.add("a11y_long_click");
}
- if ((flags & SYSUI_STATE_TRACING_ENABLED) != 0) {
- str.add("tracing");
+ if ((flags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) != 0) {
+ str.add("disable_gesture_split_invocation");
}
if ((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0) {
str.add("asst_gesture_constrain");
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 91fb6888bf06..905a98c2e181 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -35,6 +35,7 @@ import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.flags.Flags;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -134,6 +135,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final BouncerMessageInteractor mBouncerMessageInteractor;
private int mTranslationY;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final DevicePolicyManager mDevicePolicyManager;
// Whether the volume keys should be handled by keyguard. If true, then
// they will be handled here for specific media types such as music, otherwise
// the audio service will bring up the volume dialog.
@@ -460,6 +462,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
SelectedUserInteractor selectedUserInteractor,
DeviceProvisionedController deviceProvisionedController,
FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
+ DevicePolicyManager devicePolicyManager,
KeyguardTransitionInteractor keyguardTransitionInteractor,
Lazy<PrimaryBouncerInteractor> primaryBouncerInteractor,
Provider<DeviceEntryInteractor> deviceEntryInteractor
@@ -495,6 +498,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mDeviceProvisionedController = deviceProvisionedController;
mPrimaryBouncerInteractor = primaryBouncerInteractor;
+ mDevicePolicyManager = devicePolicyManager;
}
@Override
@@ -1105,35 +1109,23 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
- final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
final int failedAttemptsBeforeWipe =
- dpm.getMaximumFailedPasswordsForWipe(null, userId);
+ mDevicePolicyManager.getMaximumFailedPasswordsForWipe(null, userId);
final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0
? (failedAttemptsBeforeWipe - failedAttempts)
: Integer.MAX_VALUE; // because DPM returns 0 if no restriction
if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
- // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
- // N attempts. Once we get below the grace period, we post this dialog every time as a
- // clear warning until the deletion fires.
- // Check which profile has the strictest policy for failed password attempts
- final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
- int userType = USER_TYPE_PRIMARY;
- if (expiringUser == userId) {
- // TODO: http://b/23522538
- if (expiringUser != UserHandle.USER_SYSTEM) {
- userType = USER_TYPE_SECONDARY_USER;
- }
- } else if (expiringUser != UserHandle.USER_NULL) {
- userType = USER_TYPE_WORK_PROFILE;
- } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
- if (remainingBeforeWipe > 0) {
- mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
- } else {
- // Too many attempts. The device will be wiped shortly.
- Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
- mView.showWipeDialog(failedAttempts, userType);
- }
+ // The user has installed a DevicePolicyManager that requests a
+ // user/profile to be wiped N attempts. Once we get below the grace period,
+ // we post this dialog every time as a clear warning until the deletion
+ // fires. Check which profile has the strictest policy for failed password
+ // attempts.
+ final int expiringUser =
+ mDevicePolicyManager.getProfileWithMinimumFailedPasswordsForWipe(userId);
+ Integer mainUser = mSelectedUserInteractor.getMainUserId();
+ showMessageForFailedUnlockAttempt(
+ userId, expiringUser, mainUser, remainingBeforeWipe, failedAttempts);
}
mLockPatternUtils.reportFailedPasswordAttempt(userId);
if (timeoutMs > 0) {
@@ -1145,6 +1137,35 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
}
+ @VisibleForTesting
+ void showMessageForFailedUnlockAttempt(int userId, int expiringUserId, Integer mainUserId,
+ int remainingBeforeWipe, int failedAttempts) {
+ int userType = USER_TYPE_PRIMARY;
+ if (expiringUserId == userId) {
+ int primaryUser = UserHandle.USER_SYSTEM;
+ if (Flags.headlessSingleUserFixes()) {
+ if (mainUserId != null) {
+ primaryUser = mainUserId;
+ }
+ }
+ // TODO: http://b/23522538
+ if (expiringUserId != primaryUser) {
+ userType = USER_TYPE_SECONDARY_USER;
+ }
+ } else if (expiringUserId != UserHandle.USER_NULL) {
+ userType = USER_TYPE_WORK_PROFILE;
+ } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
+ if (remainingBeforeWipe > 0) {
+ mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe,
+ userType);
+ } else {
+ // Too many attempts. The device will be wiped shortly.
+ Slog.i(TAG, "Too many unlock attempts; user " + expiringUserId
+ + " will be wiped!");
+ mView.showWipeDialog(failedAttempts, userType);
+ }
+ }
+
private void getCurrentSecurityController(
KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback) {
mSecurityViewFlipperController
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 57c1fd091ae9..42896a419658 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -569,6 +569,11 @@ public class ExpandHelper implements Gefingerpoken {
return true;
}
+ /** Finish the current expand motion without accounting for velocity. */
+ public void finishExpanding() {
+ finishExpanding(false, 0);
+ }
+
/**
* Finish the current expand motion
* @param forceAbort whether the expansion should be forcefully aborted and returned to the old
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
index 35f9344ae897..004d5dba64c7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
@@ -22,6 +22,8 @@ import com.android.systemui.accessibility.data.repository.ColorCorrectionReposit
import com.android.systemui.accessibility.data.repository.ColorCorrectionRepositoryImpl
import com.android.systemui.accessibility.data.repository.ColorInversionRepository
import com.android.systemui.accessibility.data.repository.ColorInversionRepositoryImpl
+import com.android.systemui.accessibility.data.repository.OneHandedModeRepository
+import com.android.systemui.accessibility.data.repository.OneHandedModeRepositoryImpl
import com.android.systemui.accessibility.qs.QSAccessibilityModule
import dagger.Binds
import dagger.Module
@@ -34,6 +36,8 @@ interface AccessibilityModule {
@Binds
fun colorInversionRepository(impl: ColorInversionRepositoryImpl): ColorInversionRepository
+ @Binds fun oneHandedModeRepository(impl: OneHandedModeRepositoryImpl): OneHandedModeRepository
+
@Binds
fun accessibilityQsShortcutsRepository(
impl: AccessibilityQsShortcutsRepositoryImpl
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepository.kt
new file mode 100644
index 000000000000..d921025ba151
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepository.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/** Provides data related to one handed mode. */
+interface OneHandedModeRepository {
+ /** Observable for whether one handed mode is enabled */
+ fun isEnabled(userHandle: UserHandle): Flow<Boolean>
+
+ /** Sets one handed mode enabled state. */
+ suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean
+}
+
+@SysUISingleton
+class OneHandedModeRepositoryImpl
+@Inject
+constructor(
+ @Background private val bgCoroutineContext: CoroutineContext,
+ @Application private val scope: CoroutineScope,
+ private val secureSettings: SecureSettings,
+) : OneHandedModeRepository {
+
+ private val userMap = mutableMapOf<Int, Flow<Boolean>>()
+
+ override fun isEnabled(userHandle: UserHandle): Flow<Boolean> =
+ userMap.getOrPut(userHandle.identifier) {
+ secureSettings
+ .observerFlow(userHandle.identifier, SETTING_NAME)
+ .onStart { emit(Unit) }
+ .map {
+ secureSettings.getIntForUser(SETTING_NAME, DISABLED, userHandle.identifier) ==
+ ENABLED
+ }
+ .distinctUntilChanged()
+ .flowOn(bgCoroutineContext)
+ .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_VALUE)
+ }
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean =
+ withContext(bgCoroutineContext) {
+ secureSettings.putIntForUser(
+ SETTING_NAME,
+ if (isEnabled) ENABLED else DISABLED,
+ userHandle.identifier
+ )
+ }
+
+ companion object {
+ private const val SETTING_NAME = Settings.Secure.ONE_HANDED_MODE_ENABLED
+ private const val DISABLED = 0
+ private const val ENABLED = 1
+ private const val DEFAULT_VALUE = false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
index 99be7628b3c6..54dd6d00aa48 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
@@ -41,6 +41,10 @@ import com.android.systemui.qs.tiles.impl.inversion.domain.ColorInversionTileMap
import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionTileDataInteractor
import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionUserActionInteractor
import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
+import com.android.systemui.qs.tiles.impl.onehanded.domain.OneHandedModeTileDataInteractor
+import com.android.systemui.qs.tiles.impl.onehanded.domain.OneHandedModeTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
+import com.android.systemui.qs.tiles.impl.onehanded.ui.OneHandedModeTileMapper
import com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor.ReduceBrightColorsTileDataInteractor
import com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor.ReduceBrightColorsTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.reducebrightness.domain.model.ReduceBrightColorsTileModel
@@ -256,5 +260,24 @@ interface QSAccessibilityModule {
),
instanceId = uiEventLogger.getNewInstanceId(),
)
+
+ /** Inject One Handed Mode Tile into tileViewModelMap in QSModule. */
+ @Provides
+ @IntoMap
+ @StringKey(ONE_HANDED_TILE_SPEC)
+ fun provideOneHandedModeTileViewModel(
+ factory: QSTileViewModelFactory.Static<OneHandedModeTileModel>,
+ mapper: OneHandedModeTileMapper,
+ stateInteractor: OneHandedModeTileDataInteractor,
+ userActionInteractor: OneHandedModeTileUserActionInteractor
+ ): QSTileViewModel =
+ if (Flags.qsNewTilesFuture())
+ factory.create(
+ TileSpec.create(ONE_HANDED_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
+ else StubQSTileViewModel
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 5df7fc9865ff..fcba425f0956 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.authentication.domain.interactor
+import android.app.admin.flags.Flags
import android.os.UserHandle
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternView
@@ -288,9 +289,15 @@ constructor(
private suspend fun getWipeTarget(): WipeTarget {
// Check which profile has the strictest policy for failed authentication attempts.
val userToBeWiped = repository.getProfileWithMinFailedUnlockAttemptsForWipe()
+ val primaryUser =
+ if (Flags.headlessSingleUserFixes()) {
+ selectedUserInteractor.getMainUserId() ?: UserHandle.USER_SYSTEM
+ } else {
+ UserHandle.USER_SYSTEM
+ }
return when (userToBeWiped) {
selectedUserInteractor.getSelectedUserId() ->
- if (userToBeWiped == UserHandle.USER_SYSTEM) {
+ if (userToBeWiped == primaryUser) {
WipeTarget.WholeDevice
} else {
WipeTarget.User
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
new file mode 100644
index 000000000000..2e9169e03d80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bluetooth.qsdialog
+
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface BluetoothTileDialogModule {
+ @Binds
+ @SysUISingleton
+ fun bindDeviceItemActionInteractor(
+ impl: DeviceItemActionInteractorImpl
+ ): DeviceItemActionInteractor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
index 4369f3f64613..94f465d3c1c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
@@ -62,6 +62,7 @@ internal class BluetoothTileDialogViewModel
@Inject
constructor(
private val deviceItemInteractor: DeviceItemInteractor,
+ private val deviceItemActionInteractor: DeviceItemActionInteractor,
private val bluetoothStateInteractor: BluetoothStateInteractor,
private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor,
private val audioSharingInteractor: AudioSharingInteractor,
@@ -192,7 +193,7 @@ constructor(
// deviceItemClick is emitted when user clicked on a device item.
dialogDelegate.deviceItemClick
- .onEach { deviceItemInteractor.updateDeviceItemOnClick(it) }
+ .onEach { deviceItemActionInteractor.onClick(it, dialog) }
.launchIn(this)
// contentHeight is emitted when the dialog is dismissed.
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
new file mode 100644
index 000000000000..931176003b1b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bluetooth.qsdialog
+
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+/** Defines interface for click handling of a DeviceItem. */
+interface DeviceItemActionInteractor {
+ suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog)
+}
+
+@SysUISingleton
+open class DeviceItemActionInteractorImpl
+@Inject
+constructor(
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val logger: BluetoothTileDialogLogger,
+ private val uiEventLogger: UiEventLogger,
+) : DeviceItemActionInteractor {
+
+ override suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
+ withContext(backgroundDispatcher) {
+ logger.logDeviceClick(deviceItem.cachedBluetoothDevice.address, deviceItem.type)
+
+ deviceItem.cachedBluetoothDevice.apply {
+ when (deviceItem.type) {
+ DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE -> {
+ disconnect()
+ uiEventLogger.log(BluetoothTileDialogUiEvent.ACTIVE_DEVICE_DISCONNECT)
+ }
+ DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
+ uiEventLogger.log(BluetoothTileDialogUiEvent.AUDIO_SHARING_DEVICE_CLICKED)
+ }
+ DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE -> {
+ setActive()
+ uiEventLogger.log(BluetoothTileDialogUiEvent.CONNECTED_DEVICE_SET_ACTIVE)
+ }
+ DeviceItemType.CONNECTED_BLUETOOTH_DEVICE -> {
+ disconnect()
+ uiEventLogger.log(
+ BluetoothTileDialogUiEvent.CONNECTED_OTHER_DEVICE_DISCONNECT
+ )
+ }
+ DeviceItemType.SAVED_BLUETOOTH_DEVICE -> {
+ connect()
+ uiEventLogger.log(BluetoothTileDialogUiEvent.SAVED_DEVICE_CONNECT)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
index 66e593b94b21..1526cd9675c7 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
@@ -20,7 +20,6 @@ import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.Context
import android.media.AudioManager
-import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.BluetoothCallback
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
@@ -52,7 +51,6 @@ constructor(
private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter(),
private val localBluetoothManager: LocalBluetoothManager?,
private val systemClock: SystemClock,
- private val uiEventLogger: UiEventLogger,
private val logger: BluetoothTileDialogLogger,
@Application private val coroutineScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@@ -169,38 +167,6 @@ constructor(
)
}
- internal suspend fun updateDeviceItemOnClick(deviceItem: DeviceItem) {
- withContext(backgroundDispatcher) {
- logger.logDeviceClick(deviceItem.cachedBluetoothDevice.address, deviceItem.type)
-
- deviceItem.cachedBluetoothDevice.apply {
- when (deviceItem.type) {
- DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE -> {
- disconnect()
- uiEventLogger.log(BluetoothTileDialogUiEvent.ACTIVE_DEVICE_DISCONNECT)
- }
- DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
- uiEventLogger.log(BluetoothTileDialogUiEvent.AUDIO_SHARING_DEVICE_CLICKED)
- }
- DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE -> {
- setActive()
- uiEventLogger.log(BluetoothTileDialogUiEvent.CONNECTED_DEVICE_SET_ACTIVE)
- }
- DeviceItemType.CONNECTED_BLUETOOTH_DEVICE -> {
- disconnect()
- uiEventLogger.log(
- BluetoothTileDialogUiEvent.CONNECTED_OTHER_DEVICE_DISCONNECT
- )
- }
- DeviceItemType.SAVED_BLUETOOTH_DEVICE -> {
- connect()
- uiEventLogger.log(BluetoothTileDialogUiEvent.SAVED_DEVICE_CONNECT)
- }
- }
- }
- }
- }
-
internal fun setDeviceItemFactoryListForTesting(list: List<DeviceItemFactory>) {
deviceItemFactoryList = list
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index fa19bf478453..e0334a060ee2 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -29,7 +29,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.kotlin.BooleanFlowOperators.or
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.time.SystemClock
import dagger.Lazy
import javax.inject.Inject
@@ -78,7 +78,7 @@ constructor(
bouncerRepository.alternateBouncerUIAvailable
}
private val isDozingOrAod: Flow<Boolean> =
- or(
+ anyOf(
keyguardTransitionInteractor.get().transitionValue(KeyguardState.DOZING).map {
it > 0f
},
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index beaa170943fd..b42a903878a7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -206,7 +206,7 @@ class FalsingCollectorImpl implements FalsingCollector {
);
final CommunalInteractor communalInteractor = mCommunalInteractorLazy.get();
mJavaAdapter.alwaysCollectFlow(
- BooleanFlowOperators.INSTANCE.and(
+ BooleanFlowOperators.INSTANCE.allOf(
communalInteractor.isCommunalEnabled(),
communalInteractor.isCommunalShowing()),
this::onShowingCommunalHubChanged
@@ -292,6 +292,7 @@ class FalsingCollectorImpl implements FalsingCollector {
@Override
public void onKeyEvent(KeyEvent ev) {
+ logDebug("REAL: onKeyEvent(" + KeyEvent.actionToString(ev.getAction()) + ")");
// Only collect if it is an ACTION_UP action and is allow-listed
if (ev.getAction() == KeyEvent.ACTION_UP && mAcceptedKeycodes.contains(ev.getKeyCode())) {
mFalsingDataProvider.onKeyEvent(ev);
@@ -300,7 +301,7 @@ class FalsingCollectorImpl implements FalsingCollector {
@Override
public void onTouchEvent(MotionEvent ev) {
- logDebug("REAL: onTouchEvent(" + ev.getActionMasked() + ")");
+ logDebug("REAL: onTouchEvent(" + MotionEvent.actionToString(ev.getActionMasked()) + ")");
if (!mKeyguardStateController.isShowing()) {
avoidGesture();
return;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt
index b289fa49d06c..6b22137e455e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt
@@ -61,11 +61,11 @@ class FalsingCollectorNoOp @Inject constructor() : FalsingCollector {
}
override fun onKeyEvent(ev: KeyEvent) {
- logDebug("NOOP: onKeyEvent(${ev.action}")
+ logDebug("NOOP: onKeyEvent(${KeyEvent.actionToString(ev.action)}")
}
override fun onTouchEvent(ev: MotionEvent) {
- logDebug("NOOP: onTouchEvent(${ev.actionMasked})")
+ logDebug("NOOP: onTouchEvent(${MotionEvent.actionToString(ev.actionMasked)})")
}
override fun onMotionEventComplete() {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index b2699673f7ea..8efc66de24cd 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -18,6 +18,8 @@ package com.android.systemui.clipboardoverlay;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static com.android.systemui.Flags.screenshotShelfUi2;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -25,6 +27,7 @@ import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Context;
import android.content.res.Resources;
@@ -36,6 +39,7 @@ import android.graphics.Region;
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.MathUtils;
import android.util.TypedValue;
import android.view.DisplayCutout;
@@ -58,9 +62,15 @@ import com.android.systemui.res.R;
import com.android.systemui.screenshot.DraggableConstraintLayout;
import com.android.systemui.screenshot.FloatingWindowUtil;
import com.android.systemui.screenshot.OverlayActionChip;
+import com.android.systemui.screenshot.ui.binder.ActionButtonViewBinder;
+import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance;
+import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel;
import java.util.ArrayList;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function0;
+
/**
* Handles the visual elements and animations for the clipboard overlay.
*/
@@ -85,7 +95,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
private final DisplayMetrics mDisplayMetrics;
private final AccessibilityManager mAccessibilityManager;
- private final ArrayList<OverlayActionChip> mActionChips = new ArrayList<>();
+ private final ArrayList<View> mActionChips = new ArrayList<>();
private View mClipboardPreview;
private ImageView mImagePreview;
@@ -93,11 +103,12 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
private TextView mHiddenPreview;
private LinearLayout mMinimizedPreview;
private View mPreviewBorder;
- private OverlayActionChip mShareChip;
- private OverlayActionChip mRemoteCopyChip;
+ private View mShareChip;
+ private View mRemoteCopyChip;
private View mActionContainerBackground;
private View mDismissButton;
private LinearLayout mActionContainer;
+ private ClipboardOverlayCallbacks mClipboardCallbacks;
public ClipboardOverlayView(Context context) {
this(context, null);
@@ -128,17 +139,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
mRemoteCopyChip = requireViewById(R.id.remote_copy_chip);
mDismissButton = requireViewById(R.id.dismiss_button);
- mShareChip.setAlpha(1);
- mRemoteCopyChip.setAlpha(1);
- mShareChip.setContentDescription(mContext.getString(com.android.internal.R.string.share));
-
- mRemoteCopyChip.setIcon(
- Icon.createWithResource(mContext, R.drawable.ic_baseline_devices_24), true);
- mShareChip.setIcon(
- Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
-
- mRemoteCopyChip.setContentDescription(
- mContext.getString(R.string.clipboard_send_nearby_description));
+ bindDefaultActionChips();
mTextPreview.getViewTreeObserver().addOnPreDrawListener(() -> {
int availableHeight = mTextPreview.getHeight()
@@ -149,15 +150,68 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
super.onFinishInflate();
}
+ private void bindDefaultActionChips() {
+ if (screenshotShelfUi2()) {
+ ActionButtonViewBinder.INSTANCE.bind(mRemoteCopyChip,
+ ActionButtonViewModel.Companion.withNextId(
+ new ActionButtonAppearance(
+ Icon.createWithResource(mContext,
+ R.drawable.ic_baseline_devices_24).loadDrawable(
+ mContext),
+ null,
+ mContext.getString(R.string.clipboard_send_nearby_description)),
+ new Function0<>() {
+ @Override
+ public Unit invoke() {
+ if (mClipboardCallbacks != null) {
+ mClipboardCallbacks.onRemoteCopyButtonTapped();
+ }
+ return null;
+ }
+ }));
+ ActionButtonViewBinder.INSTANCE.bind(mShareChip,
+ ActionButtonViewModel.Companion.withNextId(
+ new ActionButtonAppearance(
+ Icon.createWithResource(mContext,
+ R.drawable.ic_screenshot_share).loadDrawable(mContext),
+ null, mContext.getString(com.android.internal.R.string.share)),
+ new Function0<>() {
+ @Override
+ public Unit invoke() {
+ if (mClipboardCallbacks != null) {
+ mClipboardCallbacks.onShareButtonTapped();
+ }
+ return null;
+ }
+ }));
+ } else {
+ mShareChip.setAlpha(1);
+ mRemoteCopyChip.setAlpha(1);
+
+ ((ImageView) mRemoteCopyChip.findViewById(R.id.overlay_action_chip_icon)).setImageIcon(
+ Icon.createWithResource(mContext, R.drawable.ic_baseline_devices_24));
+ ((ImageView) mShareChip.findViewById(R.id.overlay_action_chip_icon)).setImageIcon(
+ Icon.createWithResource(mContext, R.drawable.ic_screenshot_share));
+
+ mShareChip.setContentDescription(
+ mContext.getString(com.android.internal.R.string.share));
+ mRemoteCopyChip.setContentDescription(
+ mContext.getString(R.string.clipboard_send_nearby_description));
+ }
+ }
+
@Override
public void setCallbacks(SwipeDismissCallbacks callbacks) {
super.setCallbacks(callbacks);
ClipboardOverlayCallbacks clipboardCallbacks = (ClipboardOverlayCallbacks) callbacks;
- mShareChip.setOnClickListener(v -> clipboardCallbacks.onShareButtonTapped());
+ if (!screenshotShelfUi2()) {
+ mShareChip.setOnClickListener(v -> clipboardCallbacks.onShareButtonTapped());
+ mRemoteCopyChip.setOnClickListener(v -> clipboardCallbacks.onRemoteCopyButtonTapped());
+ }
mDismissButton.setOnClickListener(v -> clipboardCallbacks.onDismissButtonTapped());
- mRemoteCopyChip.setOnClickListener(v -> clipboardCallbacks.onRemoteCopyButtonTapped());
mClipboardPreview.setOnClickListener(v -> clipboardCallbacks.onPreviewTapped());
mMinimizedPreview.setOnClickListener(v -> clipboardCallbacks.onMinimizedViewTapped());
+ mClipboardCallbacks = clipboardCallbacks;
}
void setEditAccessibilityAction(boolean editable) {
@@ -285,7 +339,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
}
void resetActionChips() {
- for (OverlayActionChip chip : mActionChips) {
+ for (View chip : mActionChips) {
mActionContainer.removeView(chip);
}
mActionChips.clear();
@@ -437,7 +491,12 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
void setActionChip(RemoteAction action, Runnable onFinish) {
mActionContainerBackground.setVisibility(View.VISIBLE);
- OverlayActionChip chip = constructActionChip(action, onFinish);
+ View chip;
+ if (screenshotShelfUi2()) {
+ chip = constructShelfActionChip(action, onFinish);
+ } else {
+ chip = constructActionChip(action, onFinish);
+ }
mActionContainer.addView(chip);
mActionChips.add(chip);
}
@@ -450,6 +509,27 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
v.setVisibility(View.VISIBLE);
}
+ private View constructShelfActionChip(RemoteAction action, Runnable onFinish) {
+ View chip = LayoutInflater.from(mContext).inflate(
+ R.layout.shelf_action_chip, mActionContainer, false);
+ ActionButtonViewBinder.INSTANCE.bind(chip, ActionButtonViewModel.Companion.withNextId(
+ new ActionButtonAppearance(action.getIcon().loadDrawable(mContext),
+ action.getTitle(), action.getTitle()), new Function0<>() {
+ @Override
+ public Unit invoke() {
+ try {
+ action.getActionIntent().send();
+ onFinish.run();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Failed to send intent");
+ }
+ return null;
+ }
+ }));
+
+ return chip;
+ }
+
private OverlayActionChip constructActionChip(RemoteAction action, Runnable onFinish) {
OverlayActionChip chip = (OverlayActionChip) LayoutInflater.from(mContext).inflate(
R.layout.overlay_action_chip, mActionContainer, false);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
index ff9fba4c03f1..740a93eb081c 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
@@ -18,6 +18,8 @@ package com.android.systemui.clipboardoverlay.dagger;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static com.android.systemui.Flags.screenshotShelfUi2;
+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import android.content.Context;
@@ -57,8 +59,13 @@ public interface ClipboardOverlayModule {
*/
@Provides
static ClipboardOverlayView provideClipboardOverlayView(@OverlayWindowContext Context context) {
- return (ClipboardOverlayView) LayoutInflater.from(context).inflate(
- R.layout.clipboard_overlay, null);
+ if (screenshotShelfUi2()) {
+ return (ClipboardOverlayView) LayoutInflater.from(context).inflate(
+ R.layout.clipboard_overlay2, null);
+ } else {
+ return (ClipboardOverlayView) LayoutInflater.from(context).inflate(
+ R.layout.clipboard_overlay, null);
+ }
}
@Qualifier
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
index 07814512b4b8..85e2bdb43ba5 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
@@ -37,7 +37,7 @@ import kotlinx.coroutines.DisposableHandle
class LongPressHandlingView(
context: Context,
attrs: AttributeSet?,
- private val longPressDuration: () -> Long,
+ longPressDuration: () -> Long,
) :
View(
context,
@@ -89,6 +89,12 @@ class LongPressHandlingView(
)
}
+ var longPressDuration: () -> Long
+ get() = interactionHandler.longPressDuration
+ set(longPressDuration) {
+ interactionHandler.longPressDuration = longPressDuration
+ }
+
fun setLongPressHandlingEnabled(isEnabled: Boolean) {
interactionHandler.isLongPressHandlingEnabled = isEnabled
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
index a742e8d614b1..d3fc610bc52e 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
@@ -34,7 +34,7 @@ class LongPressHandlingViewInteractionHandler(
/** Callback reporting the a single tap gesture was detected at the given coordinates. */
private val onSingleTapDetected: () -> Unit,
/** Time for the touch to be considered a long-press in ms */
- private val longPressDuration: () -> Long,
+ var longPressDuration: () -> Long,
) {
sealed class MotionEventModel {
object Other : MotionEventModel()
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 0042915d0cd9..5091a99b2a64 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -60,9 +60,9 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.UserTracker
import com.android.systemui.smartspace.data.repository.SmartspaceRepository
-import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
-import com.android.systemui.util.kotlin.BooleanFlowOperators.or
import com.android.systemui.util.kotlin.emitOnStart
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -127,10 +127,10 @@ constructor(
/** Whether communal features are enabled and available. */
val isCommunalAvailable: Flow<Boolean> =
- and(
+ allOf(
communalSettingsInteractor.isCommunalEnabled,
not(keyguardInteractor.isEncryptedOrLockdown),
- or(keyguardInteractor.isKeyguardShowing, keyguardInteractor.isDreaming)
+ anyOf(keyguardInteractor.isKeyguardShowing, keyguardInteractor.isDreaming)
)
.distinctUntilChanged()
.onEach { available ->
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
index 8390d62b23db..2ccab072d57f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
@@ -23,7 +23,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
-import com.android.systemui.util.kotlin.BooleanFlowOperators.or
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -46,7 +46,7 @@ constructor(
) : CoreStartable {
override fun start() {
- or(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen)
+ anyOf(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen)
// Only trigger updates on state changes, ignoring the initial false value.
.pairwise(false)
.filter { (previous, new) -> previous != new }
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
index ba45a51ad9a3..30a56a21e322 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -46,7 +46,6 @@ import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthR
import com.android.systemui.keyguard.data.repository.FaceAuthTableLog
import com.android.systemui.keyguard.data.repository.FaceDetectTableLog
import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -64,6 +63,7 @@ import com.android.systemui.user.data.repository.UserRepository
import com.google.errorprone.annotations.CompileTimeConstant
import java.io.PrintWriter
import java.util.Arrays
+import java.util.concurrent.Executor
import java.util.stream.Collectors
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -150,12 +150,12 @@ constructor(
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ @Background private val backgroundExecutor: Executor,
private val sessionTracker: SessionTracker,
private val uiEventsLogger: UiEventLogger,
private val faceAuthLogger: FaceAuthenticationLogger,
private val biometricSettingsRepository: BiometricSettingsRepository,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
- trustRepository: TrustRepository,
private val keyguardRepository: KeyguardRepository,
private val powerInteractor: PowerInteractor,
private val keyguardInteractor: KeyguardInteractor,
@@ -235,7 +235,10 @@ constructor(
}
init {
- faceManager?.addLockoutResetCallback(faceLockoutResetCallback)
+ backgroundExecutor.execute {
+ faceManager?.addLockoutResetCallback(faceLockoutResetCallback)
+ faceAuthLogger.addLockoutResetCallbackDone()
+ }
faceAcquiredInfoIgnoreList =
Arrays.stream(
context.resources.getIntArray(
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 662974dd2c91..d079a954cb57 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -240,6 +240,15 @@ constructor(
}
/**
+ * Whether the lockscreen is enabled for the current user. This is `true` whenever the user has
+ * chosen any secure authentication method and even if they set the lockscreen to be dismissed
+ * when the user swipes on it.
+ */
+ suspend fun isLockscreenEnabled(): Boolean {
+ return repository.isLockscreenEnabled()
+ }
+
+ /**
* Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically
* dismissed once the authentication challenge is completed. For example, completing a biometric
* authentication challenge via face unlock or fingerprint sensor can automatically bypass the
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
index c6fb4f9d6956..fc9406bd27d8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
@@ -19,12 +19,13 @@ package com.android.systemui.keyboard
import com.android.systemui.keyboard.data.repository.KeyboardRepository
import com.android.systemui.keyboard.data.repository.KeyboardRepositoryImpl
+import com.android.systemui.keyboard.shortcut.ShortcutHelperModule
import com.android.systemui.keyboard.stickykeys.data.repository.StickyKeysRepository
import com.android.systemui.keyboard.stickykeys.data.repository.StickyKeysRepositoryImpl
import dagger.Binds
import dagger.Module
-@Module
+@Module(includes = [ShortcutHelperModule::class])
abstract class KeyboardModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
new file mode 100644
index 000000000000..5635f8056b9c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut
+
+import android.app.Activity
+import com.android.systemui.CoreStartable
+import com.android.systemui.Flags.keyboardShortcutHelperRewrite
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperRepository
+import com.android.systemui.keyboard.shortcut.ui.ShortcutHelperActivityStarter
+import com.android.systemui.keyboard.shortcut.ui.view.ShortcutHelperActivity
+import dagger.Binds
+import dagger.Lazy
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface ShortcutHelperModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(ShortcutHelperActivity::class)
+ fun activity(impl: ShortcutHelperActivity): Activity
+
+ companion object {
+ @Provides
+ @IntoMap
+ @ClassKey(ShortcutHelperActivityStarter::class)
+ fun starter(implLazy: Lazy<ShortcutHelperActivityStarter>): CoreStartable {
+ return if (keyboardShortcutHelperRewrite()) {
+ implLazy.get()
+ } else {
+ // No-op implementation when the flag is disabled.
+ NoOpStartable
+ }
+ }
+
+ @Provides
+ @IntoMap
+ @ClassKey(ShortcutHelperRepository::class)
+ fun repo(implLazy: Lazy<ShortcutHelperRepository>): CoreStartable {
+ return if (keyboardShortcutHelperRewrite()) {
+ implLazy.get()
+ } else {
+ // No-op implementation when the flag is disabled.
+ NoOpStartable
+ }
+ }
+ }
+}
+
+private object NoOpStartable : CoreStartable {
+ override fun start() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperRepository.kt
new file mode 100644
index 000000000000..9450af4c804e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperRepository.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.data.repository
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import com.android.systemui.CoreStartable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Inactive
+import com.android.systemui.statusbar.CommandQueue
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+@SysUISingleton
+class ShortcutHelperRepository
+@Inject
+constructor(
+ private val commandQueue: CommandQueue,
+ private val broadcastDispatcher: BroadcastDispatcher,
+) : CoreStartable {
+
+ val state = MutableStateFlow<ShortcutHelperState>(Inactive)
+
+ override fun start() {
+ registerBroadcastReceiver(
+ action = Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS,
+ onReceive = { state.value = Active() }
+ )
+ registerBroadcastReceiver(
+ action = Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS,
+ onReceive = { state.value = Inactive }
+ )
+ commandQueue.addCallback(
+ object : CommandQueue.Callbacks {
+ override fun dismissKeyboardShortcutsMenu() {
+ state.value = Inactive
+ }
+
+ override fun toggleKeyboardShortcutsMenu(deviceId: Int) {
+ state.value =
+ if (state.value is Inactive) {
+ Active(deviceId)
+ } else {
+ Inactive
+ }
+ }
+ }
+ )
+ }
+
+ fun hide() {
+ state.value = Inactive
+ }
+
+ private fun registerBroadcastReceiver(action: String, onReceive: () -> Unit) {
+ broadcastDispatcher.registerReceiver(
+ receiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ onReceive()
+ }
+ },
+ filter = IntentFilter(action),
+ flags = Context.RECEIVER_EXPORTED or Context.RECEIVER_VISIBLE_TO_INSTANT_APPS
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperInteractor.kt
new file mode 100644
index 000000000000..d3f7e24bb87f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperInteractor.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperRepository
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class ShortcutHelperInteractor
+@Inject
+constructor(private val repository: ShortcutHelperRepository) {
+
+ val state: Flow<ShortcutHelperState> = repository.state
+
+ fun onUserLeave() {
+ repository.hide()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutHelperState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutHelperState.kt
new file mode 100644
index 000000000000..d22d6c88ccc8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutHelperState.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.shared.model
+
+sealed interface ShortcutHelperState {
+ data object Inactive : ShortcutHelperState
+
+ data class Active(val deviceId: Int? = null) : ShortcutHelperState
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarter.kt
new file mode 100644
index 000000000000..fbf52e773599
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarter.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.ui
+
+import android.content.Context
+import android.content.Intent
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyboard.shortcut.ui.view.ShortcutHelperActivity
+import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class ShortcutHelperActivityStarter(
+ private val context: Context,
+ @Application private val applicationScope: CoroutineScope,
+ private val viewModel: ShortcutHelperViewModel,
+ private val startActivity: (Intent) -> Unit,
+) : CoreStartable {
+
+ @Inject
+ constructor(
+ context: Context,
+ @Application applicationScope: CoroutineScope,
+ viewModel: ShortcutHelperViewModel,
+ ) : this(
+ context,
+ applicationScope,
+ viewModel,
+ startActivity = { intent -> context.startActivity(intent) }
+ )
+
+ override fun start() {
+ applicationScope.launch {
+ viewModel.shouldShow.collect { shouldShow ->
+ if (shouldShow) {
+ startShortcutHelperActivity()
+ }
+ }
+ }
+ }
+
+ private fun startShortcutHelperActivity() {
+ startActivity(
+ Intent(context, ShortcutHelperActivity::class.java)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperActivity.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
index 692fbb06e88c..934f9ee9e90d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyboard.shortcut
+package com.android.systemui.keyboard.shortcut.ui.view
import android.graphics.Insets
import android.os.Bundle
@@ -24,16 +24,25 @@ import androidx.activity.BackEventCompat
import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.core.view.updatePadding
+import androidx.lifecycle.flowWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
import com.android.systemui.res.R
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
+import javax.inject.Inject
+import kotlinx.coroutines.launch
/**
* Activity that hosts the new version of the keyboard shortcut helper. It will be used both for
* small and large screen devices.
*/
-class ShortcutHelperActivity : ComponentActivity() {
+class ShortcutHelperActivity
+@Inject
+constructor(
+ private val viewModel: ShortcutHelperViewModel,
+) : ComponentActivity() {
private val bottomSheetContainer
get() = requireViewById<View>(R.id.shortcut_helper_sheet_container)
@@ -53,6 +62,24 @@ class ShortcutHelperActivity : ComponentActivity() {
setUpPredictiveBack()
setUpSheetDismissListener()
setUpDismissOnTouchOutside()
+ observeFinishRequired()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (isFinishing) {
+ viewModel.onUserLeave()
+ }
+ }
+
+ private fun observeFinishRequired() {
+ lifecycleScope.launch {
+ viewModel.shouldShow.flowWithLifecycle(lifecycle).collect { shouldShow ->
+ if (!shouldShow) {
+ finish()
+ }
+ }
+ }
}
private fun setupEdgeToEdge() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
new file mode 100644
index 000000000000..7e48c6523122
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.ui.viewmodel
+
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperInteractor
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+
+class ShortcutHelperViewModel
+@Inject
+constructor(
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val interactor: ShortcutHelperInteractor
+) {
+
+ val shouldShow =
+ interactor.state
+ .map { it is ShortcutHelperState.Active }
+ .distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
+
+ fun onUserLeave() {
+ interactor.onUserLeave()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
index 4a726ae3aafc..a49b3ae7b7e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
@@ -65,23 +65,43 @@ constructor(
* @param blueprintId
* @return whether the transition has succeeded.
*/
+ fun applyBlueprint(index: Int): Boolean {
+ ArrayList(blueprintIdMap.values)[index]?.let {
+ applyBlueprint(it)
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Emits the blueprint value to the collectors.
+ *
+ * @param blueprintId
+ * @return whether the transition has succeeded.
+ */
fun applyBlueprint(blueprintId: String?): Boolean {
val blueprint = blueprintIdMap[blueprintId]
- if (blueprint == null) {
+ return if (blueprint != null) {
+ applyBlueprint(blueprint)
+ true
+ } else {
Log.e(
TAG,
"Could not find blueprint with id: $blueprintId. " +
"Perhaps it was not added to KeyguardBlueprintModule?"
)
- return false
+ false
}
+ }
+ /** Emits the blueprint value to the collectors. */
+ fun applyBlueprint(blueprint: KeyguardBlueprint?) {
if (blueprint == this.blueprint.value) {
- return true
+ refreshBlueprint()
+ return
}
- this.blueprint.value = blueprint
- return true
+ blueprint?.let { this.blueprint.value = it }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 4c54bfd3a17c..e32bfcf81fe2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -89,6 +89,12 @@ interface KeyguardTransitionRepository {
suspend fun startTransition(info: TransitionInfo): UUID?
/**
+ * Emits STARTED and FINISHED transition steps to the given state. This is used during boot to
+ * seed the repository with the appropriate initial state.
+ */
+ suspend fun emitInitialStepsFromOff(to: KeyguardState)
+
+ /**
* Allows manual control of a transition. When calling [startTransition], the consumer must pass
* in a null animator. In return, it will get a unique [UUID] that will be validated to allow
* further updates.
@@ -141,9 +147,17 @@ constructor(
private var updateTransitionId: UUID? = null
init {
- // Seed with transitions signaling a boot into lockscreen state. If updating this, please
- // also update FakeKeyguardTransitionRepository.
- initialTransitionSteps.forEach(::emitTransition)
+ // Start with a FINISHED transition in OFF. KeyguardBootInteractor will transition from OFF
+ // to either GONE or LOCKSCREEN once we're booted up and can determine which state we should
+ // start in.
+ emitTransition(
+ TransitionStep(
+ KeyguardState.OFF,
+ KeyguardState.OFF,
+ 1f,
+ TransitionState.FINISHED,
+ )
+ )
}
override suspend fun startTransition(info: TransitionInfo): UUID? {
@@ -251,6 +265,28 @@ constructor(
lastStep = nextStep
}
+ override suspend fun emitInitialStepsFromOff(to: KeyguardState) {
+ emitTransition(
+ TransitionStep(
+ KeyguardState.OFF,
+ to,
+ 0f,
+ TransitionState.STARTED,
+ ownerName = "KeyguardTransitionRepository(boot)",
+ )
+ )
+
+ emitTransition(
+ TransitionStep(
+ KeyguardState.OFF,
+ to,
+ 1f,
+ TransitionState.FINISHED,
+ ownerName = "KeyguardTransitionRepository(boot)",
+ ),
+ )
+ }
+
private fun logAndTrace(step: TransitionStep, isManual: Boolean) {
if (step.transitionState == TransitionState.RUNNING) {
return
@@ -271,31 +307,5 @@ constructor(
companion object {
private const val TAG = "KeyguardTransitionRepository"
-
- /**
- * Transition steps to seed the repository with, so that all of the transition interactor
- * flows emit reasonable initial values.
- */
- val initialTransitionSteps: List<TransitionStep> =
- listOf(
- TransitionStep(
- KeyguardState.OFF,
- KeyguardState.OFF,
- 1f,
- TransitionState.FINISHED,
- ),
- TransitionStep(
- KeyguardState.OFF,
- KeyguardState.LOCKSCREEN,
- 0f,
- TransitionState.STARTED,
- ),
- TransitionStep(
- KeyguardState.OFF,
- KeyguardState.LOCKSCREEN,
- 1f,
- TransitionState.FINISHED,
- ),
- )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 2eeb3b947a11..115fc3610ac8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -66,7 +66,7 @@ constructor(
listenForTransitionToCamera(scope, keyguardInteractor)
}
- private val canDismissLockScreen: Flow<Boolean> =
+ private val canTransitionToGoneOnWake: Flow<Boolean> =
combine(
keyguardInteractor.isKeyguardShowing,
keyguardInteractor.isKeyguardDismissible,
@@ -87,7 +87,7 @@ constructor(
keyguardInteractor.biometricUnlockState,
keyguardInteractor.isKeyguardOccluded,
communalInteractor.isIdleOnCommunal,
- canDismissLockScreen,
+ canTransitionToGoneOnWake,
keyguardInteractor.primaryBouncerShowing,
)
.collect {
@@ -96,12 +96,12 @@ constructor(
biometricUnlockState,
occluded,
isIdleOnCommunal,
- canDismissLockScreen,
+ canTransitionToGoneOnWake,
primaryBouncerShowing) ->
startTransitionTo(
if (isWakeAndUnlock(biometricUnlockState.mode)) {
KeyguardState.GONE
- } else if (canDismissLockScreen) {
+ } else if (canTransitionToGoneOnWake) {
KeyguardState.GONE
} else if (primaryBouncerShowing) {
KeyguardState.PRIMARY_BOUNCER
@@ -129,7 +129,7 @@ constructor(
.sample(
communalInteractor.isIdleOnCommunal,
keyguardInteractor.biometricUnlockState,
- canDismissLockScreen,
+ canTransitionToGoneOnWake,
keyguardInteractor.primaryBouncerShowing,
)
.collect {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 54d9a78620e5..faab033441c1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -28,7 +28,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@@ -148,7 +148,7 @@ constructor(
}
} else {
scope.launch {
- and(keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isDreaming))
+ allOf(keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isDreaming))
.filterRelevantKeyguardStateAnd { isOccludedAndNotDreaming ->
isOccludedAndNotDreaming
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index cf995faea77d..da4f85e0dd2f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -82,17 +82,12 @@ constructor(
}
/**
- * Transitions to a blueprint, or refreshes it if already applied.
+ * Transitions to a blueprint.
*
* @param blueprintId
* @return whether the transition has succeeded.
*/
- fun transitionOrRefreshBlueprint(blueprintId: String): Boolean {
- if (blueprintId == blueprint.value.id) {
- refreshBlueprint()
- return true
- }
-
+ fun transitionToBlueprint(blueprintId: String): Boolean {
return keyguardBlueprintRepository.applyBlueprint(blueprintId)
}
@@ -102,7 +97,7 @@ constructor(
* @param blueprintId
* @return whether the transition has succeeded.
*/
- fun transitionToBlueprint(blueprintId: String): Boolean {
+ fun transitionToBlueprint(blueprintId: Int): Boolean {
return keyguardBlueprintRepository.applyBlueprint(blueprintId)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
index 20b7b2a91ade..82255a0c0d54 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
@@ -31,6 +31,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
/**
* Distance over which the surface behind the keyguard is animated in during a Y-translation
@@ -102,8 +103,11 @@ constructor(
*/
private val isNotificationLaunchAnimationRunningOnKeyguard =
notificationLaunchInteractor.isLaunchAnimationRunning
- .sample(transitionInteractor.finishedKeyguardState)
- .map { it != KeyguardState.GONE }
+ .sample(transitionInteractor.finishedKeyguardState, ::Pair)
+ .map { (animationRunning, finishedState) ->
+ animationRunning && finishedState != KeyguardState.GONE
+ }
+ .onStart { emit(false) }
/**
* Whether we're animating the surface, or a notification launch animation is running (which
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
new file mode 100644
index 000000000000..5ad7762bb512
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.util.Log
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+/** Handles initialization of the KeyguardTransitionRepository on boot. */
+@SysUISingleton
+class KeyguardTransitionBootInteractor
+@Inject
+constructor(
+ @Application val scope: CoroutineScope,
+ val deviceEntryInteractor: DeviceEntryInteractor,
+ val deviceProvisioningInteractor: DeviceProvisioningInteractor,
+ val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ val repository: KeyguardTransitionRepository,
+) : CoreStartable {
+
+ /**
+ * Whether the lockscreen should be showing when the device starts up for the first time. If not
+ * then we'll seed the repository with a transition from OFF -> GONE.
+ */
+ @OptIn(ExperimentalCoroutinesApi::class)
+ private val showLockscreenOnBoot =
+ deviceProvisioningInteractor.isDeviceProvisioned.map { provisioned ->
+ (provisioned || deviceEntryInteractor.isAuthenticationRequired()) &&
+ deviceEntryInteractor.isLockscreenEnabled()
+ }
+
+ override fun start() {
+ scope.launch {
+ val state =
+ if (showLockscreenOnBoot.first()) {
+ KeyguardState.LOCKSCREEN
+ } else {
+ KeyguardState.GONE
+ }
+
+ if (
+ keyguardTransitionInteractor.currentTransitionInfoInternal.value.from !=
+ KeyguardState.OFF
+ ) {
+ Log.e(
+ "KeyguardTransitionInteractor",
+ "showLockscreenOnBoot emitted, but we've already " +
+ "transitioned to a state other than OFF. We'll respect that " +
+ "transition, but this should not happen."
+ )
+ } else {
+ repository.emitInitialStepsFromOff(state)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index 91f8420393e1..31b0bf7fe425 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -27,6 +27,7 @@ class KeyguardTransitionCoreStartable
constructor(
private val interactors: Set<TransitionInteractor>,
private val auditLogger: KeyguardTransitionAuditLogger,
+ private val bootInteractor: KeyguardTransitionBootInteractor,
) : CoreStartable {
override fun start() {
@@ -51,6 +52,7 @@ constructor(
it.start()
}
auditLogger.start()
+ bootInteractor.start()
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index db47bfbd4cd4..4f00495819e8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -34,6 +34,7 @@ import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -94,6 +95,24 @@ object DeviceEntryIconViewBinder {
longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
}
}
+ launch("$TAG#viewModel.isUdfpsSupported") {
+ viewModel.isUdfpsSupported.collect { udfpsSupported ->
+ longPressHandlingView.longPressDuration =
+ if (udfpsSupported) {
+ {
+ view.resources
+ .getInteger(R.integer.config_udfpsDeviceEntryIconLongPress)
+ .toLong()
+ }
+ } else {
+ {
+ view.resources
+ .getInteger(R.integer.config_lockIconLongPress)
+ .toLong()
+ }
+ }
+ }
+ }
launch("$TAG#viewModel.accessibilityDelegateHint") {
viewModel.accessibilityDelegateHint.collect { hint ->
view.accessibilityHintType = hint
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
index abd79ab793d5..b9a79dccf76b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
@@ -118,6 +118,7 @@ object KeyguardQuickAffordanceViewBinder {
}
override fun destroy() {
+ view.setOnApplyWindowInsetsListener(null)
disposableHandle.dispose()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
index a8e9041abfd7..0f63f65e4511 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -41,6 +41,7 @@ import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransition
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.OffToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToDozingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel
@@ -196,6 +197,12 @@ abstract class DeviceEntryIconTransitionModule {
@Binds
@IntoSet
+ abstract fun offToLockscreen(
+ impl: OffToLockscreenTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
abstract fun primaryBouncerToAod(
impl: PrimaryBouncerToAodTransitionViewModel
): DeviceEntryIconTransition
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
index 5713a158fde4..35b259849b78 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
@@ -40,10 +40,7 @@ constructor(
attrs: AttributeSet?,
defStyleAttrs: Int = 0,
) : FrameLayout(context, attrs, defStyleAttrs) {
- val longPressHandlingView: LongPressHandlingView =
- LongPressHandlingView(context, attrs) {
- context.resources.getInteger(R.integer.config_lockIconLongPress).toLong()
- }
+ val longPressHandlingView: LongPressHandlingView = LongPressHandlingView(context, attrs)
val iconView: ImageView = ImageView(context, attrs).apply { id = R.id.device_entry_icon_fg }
val bgView: ImageView = ImageView(context, attrs).apply { id = R.id.device_entry_icon_bg }
val aodFpDrawable: LottieDrawable = LottieDrawable()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt
index 962cdf10cf86..ce7ec0e22f1c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt
@@ -46,14 +46,15 @@ constructor(
return
}
- when {
- arg.isDigitsOnly() -> pw.println("Invalid argument! Use string ids.")
- keyguardBlueprintInteractor.transitionOrRefreshBlueprint(arg) ->
- pw.println("Transition succeeded!")
- else -> {
- pw.println("Invalid argument! To see available blueprint ids, run:")
- pw.println("$ adb shell cmd statusbar blueprint help")
- }
+ if (
+ arg.isDigitsOnly() && keyguardBlueprintInteractor.transitionToBlueprint(arg.toInt())
+ ) {
+ pw.println("Transition succeeded!")
+ } else if (keyguardBlueprintInteractor.transitionToBlueprint(arg)) {
+ pw.println("Transition succeeded!")
+ } else {
+ pw.println("Invalid argument! To see available blueprint ids, run:")
+ pw.println("$ adb shell cmd statusbar blueprint help")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
index 45b82576c6c4..9146c605ab63 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.ui.view.layout.sections
import android.content.res.Resources
+import android.view.WindowInsets
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
@@ -25,15 +26,19 @@ import androidx.constraintlayout.widget.ConstraintSet.LEFT
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.RIGHT
import androidx.constraintlayout.widget.ConstraintSet.VISIBILITY_MODE_IGNORE
+import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
+import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.statusbar.KeyguardIndicationController
import com.android.systemui.statusbar.VibratorHelper
+import dagger.Lazy
import javax.inject.Inject
class DefaultShortcutsSection
@@ -46,11 +51,29 @@ constructor(
private val falsingManager: FalsingManager,
private val indicationController: KeyguardIndicationController,
private val vibratorHelper: VibratorHelper,
+ private val keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
) : BaseShortcutSection() {
+
+ // Amount to increase the bottom margin by to avoid colliding with inset
+ private var safeInsetBottom = 0
+
override fun addViews(constraintLayout: ConstraintLayout) {
if (KeyguardBottomAreaRefactor.isEnabled) {
addLeftShortcut(constraintLayout)
addRightShortcut(constraintLayout)
+
+ constraintLayout
+ .requireViewById<LaunchableImageView>(R.id.start_button)
+ .setOnApplyWindowInsetsListener { _, windowInsets ->
+ val tempSafeInset = windowInsets?.displayCutout?.safeInsetBottom ?: 0
+ if (safeInsetBottom != tempSafeInset) {
+ safeInsetBottom = tempSafeInset
+ keyguardBlueprintInteractor
+ .get()
+ .refreshBlueprint(IntraBlueprintTransition.Type.DefaultTransition)
+ }
+ WindowInsets.CONSUMED
+ }
}
}
@@ -91,12 +114,24 @@ constructor(
constrainWidth(R.id.start_button, width)
constrainHeight(R.id.start_button, height)
connect(R.id.start_button, LEFT, PARENT_ID, LEFT, horizontalOffsetMargin)
- connect(R.id.start_button, BOTTOM, PARENT_ID, BOTTOM, verticalOffsetMargin)
+ connect(
+ R.id.start_button,
+ BOTTOM,
+ PARENT_ID,
+ BOTTOM,
+ verticalOffsetMargin + safeInsetBottom
+ )
constrainWidth(R.id.end_button, width)
constrainHeight(R.id.end_button, height)
connect(R.id.end_button, RIGHT, PARENT_ID, RIGHT, horizontalOffsetMargin)
- connect(R.id.end_button, BOTTOM, PARENT_ID, BOTTOM, verticalOffsetMargin)
+ connect(
+ R.id.end_button,
+ BOTTOM,
+ PARENT_ID,
+ BOTTOM,
+ verticalOffsetMargin + safeInsetBottom
+ )
// The constraint set visibility for start and end button are default visible, set to
// ignore so the view's own initial visibility (invisible) is used
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index 7c29b39ad12c..218967c338ea 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -38,6 +38,8 @@ import com.android.systemui.shared.R as sharedR
import com.google.android.material.math.MathUtils
import kotlin.math.abs
+internal fun View.getRect(): Rect = Rect(this.left, this.top, this.right, this.bottom)
+
internal fun View.setRect(rect: Rect) =
this.setLeftTopRightBottom(rect.left, rect.top, rect.right, rect.bottom)
@@ -66,12 +68,18 @@ class ClockSizeTransition(
val view = transition.view
transition.values[PROP_VISIBILITY] = view.visibility
transition.values[PROP_ALPHA] = view.alpha
- transition.values[PROP_BOUNDS] = Rect(view.left, view.top, view.right, view.bottom)
+ transition.values[PROP_BOUNDS] = view.getRect()
if (!captureSmartspace) return
- val ss = (view.parent as View).findViewById<View>(sharedR.id.bc_smartspace_view)
- if (ss == null) return
- transition.values[SMARTSPACE_BOUNDS] = Rect(ss.left, ss.top, ss.right, ss.bottom)
+ val parent = view.parent as View
+ val targetSSView =
+ parent.findViewById<View>(sharedR.id.bc_smartspace_view)
+ ?: parent.findViewById<View>(R.id.keyguard_slice_view)
+ if (targetSSView == null) {
+ Log.e(TAG, "Failed to find smartspace equivalent target for animation")
+ return
+ }
+ transition.values[SMARTSPACE_BOUNDS] = targetSSView.getRect()
}
open fun mutateBounds(
@@ -89,7 +97,13 @@ class ClockSizeTransition(
startValues: TransitionValues?,
endValues: TransitionValues?
): Animator? {
- if (startValues == null || endValues == null) return null
+ if (startValues == null || endValues == null) {
+ Log.w(
+ TAG,
+ "Couldn't create animator: startValues=$startValues; endValues=$endValues"
+ )
+ return null
+ }
var fromVis = startValues.values[PROP_VISIBILITY] as Int
var fromIsVis = fromVis == View.VISIBLE
@@ -141,11 +155,12 @@ class ClockSizeTransition(
fun assignAnimValues(src: String, fract: Float, vis: Int? = null) {
val bounds = computeBounds(fract)
val alpha = MathUtils.lerp(fromAlpha, toAlpha, fract)
- if (DEBUG)
+ if (DEBUG) {
Log.i(
TAG,
"$src: $toView; fract=$fract; alpha=$alpha; vis=$vis; bounds=$bounds;"
)
+ }
toView.setVisibility(vis ?: View.VISIBLE)
toView.setAlpha(alpha)
toView.setRect(bounds)
@@ -245,12 +260,9 @@ class ClockSizeTransition(
// Move normally if clock is not changing visibility
if (fromIsVis == toIsVis) return
- fromBounds.left = toBounds.left
- fromBounds.right = toBounds.right
+ fromBounds.set(toBounds)
if (viewModel.isLargeClockVisible.value) {
- // Large clock shouldn't move
- fromBounds.top = toBounds.top
- fromBounds.bottom = toBounds.bottom
+ // Large clock shouldn't move; fromBounds already set
} else if (toSSBounds != null && fromSSBounds != null) {
// Instead of moving the small clock the full distance, we compute the distance
// smartspace will move. We then scale this to match the duration of this animation
@@ -306,12 +318,9 @@ class ClockSizeTransition(
// Move normally if clock is not changing visibility
if (fromIsVis == toIsVis) return
- toBounds.left = fromBounds.left
- toBounds.right = fromBounds.right
+ toBounds.set(fromBounds)
if (!viewModel.isLargeClockVisible.value) {
- // Large clock shouldn't move
- toBounds.top = fromBounds.top
- toBounds.bottom = fromBounds.bottom
+ // Large clock shouldn't move; toBounds already set
} else if (toSSBounds != null && fromSSBounds != null) {
// Instead of moving the small clock the full distance, we compute the distance
// smartspace will move. We then scale this to match the duration of this animation
@@ -321,7 +330,7 @@ class ClockSizeTransition(
toBounds.top = fromBounds.top - ssTranslation
toBounds.bottom = fromBounds.bottom - ssTranslation
} else {
- Log.w(TAG, "mutateBounds: smallClock received no smartspace bounds")
+ Log.e(TAG, "mutateBounds: smallClock received no smartspace bounds")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index 40be73e5e9dc..da2fcc48a13d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -84,19 +84,21 @@ constructor(
.map { it.deviceEntryParentViewAlpha }
.merge()
.shareIn(scope, SharingStarted.WhileSubscribed())
+ .onStart { emit(initialAlphaFromKeyguardState(transitionInteractor.getCurrentState())) }
private val alphaMultiplierFromShadeExpansion: Flow<Float> =
combine(
- showingAlternateBouncer,
- shadeExpansion,
- qsProgress,
- ) { showingAltBouncer, shadeExpansion, qsProgress ->
- val interpolatedQsProgress = (qsProgress * 2).coerceIn(0f, 1f)
- if (showingAltBouncer) {
- 1f
- } else {
- (1f - shadeExpansion) * (1f - interpolatedQsProgress)
+ showingAlternateBouncer,
+ shadeExpansion,
+ qsProgress,
+ ) { showingAltBouncer, shadeExpansion, qsProgress ->
+ val interpolatedQsProgress = (qsProgress * 2).coerceIn(0f, 1f)
+ if (showingAltBouncer) {
+ 1f
+ } else {
+ (1f - shadeExpansion) * (1f - interpolatedQsProgress)
+ }
}
- }
+ .onStart { emit(1f) }
// Burn-in offsets in AOD
private val nonAnimatedBurnInOffsets: Flow<BurnInOffsets> =
combine(
@@ -122,14 +124,34 @@ constructor(
)
}
- val deviceEntryViewAlpha: StateFlow<Float> =
+ val deviceEntryViewAlpha: Flow<Float> =
combine(
transitionAlpha,
alphaMultiplierFromShadeExpansion,
) { alpha, alphaMultiplier ->
alpha * alphaMultiplier
}
- .stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initialValue = 0f)
+ .stateIn(
+ scope = scope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = 0f,
+ )
+
+ private fun initialAlphaFromKeyguardState(keyguardState: KeyguardState): Float {
+ return when (keyguardState) {
+ KeyguardState.OFF,
+ KeyguardState.PRIMARY_BOUNCER,
+ KeyguardState.DOZING,
+ KeyguardState.DREAMING,
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.GONE,
+ KeyguardState.OCCLUDED,
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED, -> 0f
+ KeyguardState.AOD,
+ KeyguardState.ALTERNATE_BOUNCER,
+ KeyguardState.LOCKSCREEN -> 1f
+ }
+ }
val useBackgroundProtection: StateFlow<Boolean> = isUdfpsSupported
val burnInOffsets: Flow<BurnInOffsets> =
deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 24a7c512a6a9..bbcea56799ea 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -42,7 +42,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.util.kotlin.BooleanFlowOperators.or
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.ui.AnimatableEvent
@@ -64,7 +64,6 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.launch
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
@@ -134,7 +133,7 @@ constructor(
private val isOnLockscreen: Flow<Boolean> =
combine(
keyguardTransitionInteractor.isFinishedInState(LOCKSCREEN).onStart { emit(false) },
- or(
+ anyOf(
keyguardTransitionInteractor.isInTransitionToState(LOCKSCREEN),
keyguardTransitionInteractor.isInTransitionFromState(LOCKSCREEN),
),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index 2c1e75e2263b..d8b50133949d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -100,7 +100,13 @@ constructor(
// Swiping down from the top edge goes to QS (or shade if in split shade mode).
swipeDownFromTop(pointerCount = 1) to quickSettingsIfSingleShade,
- swipeDownFromTop(pointerCount = 2) to quickSettingsIfSingleShade,
+ swipeDownFromTop(pointerCount = 2) to
+ // TODO(b/338577208): Remove 'Dual' once we add Dual Shade invocation zones.
+ if (shadeMode is ShadeMode.Dual) {
+ Scenes.QuickSettingsShade
+ } else {
+ quickSettingsIfSingleShade
+ },
// Swiping down, not from the edge, always navigates to the shade scene.
swipeDown(pointerCount = 1) to shadeSceneKey,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt
index 74094bea140a..cf6a533ed76b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
@@ -28,7 +29,7 @@ class OffToLockscreenTransitionViewModel
@Inject
constructor(
animationFlow: KeyguardTransitionAnimationFlow,
-) {
+) : DeviceEntryIconTransition {
private val transitionAnimation =
animationFlow.setup(
@@ -43,4 +44,7 @@ constructor(
onStep = { it },
onCancel = { 0f },
)
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(1f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
index 9e6c5520d1b7..b276f532e874 100644
--- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -201,6 +201,10 @@ constructor(
)
}
+ fun addLockoutResetCallbackDone() {
+ logBuffer.log(TAG, DEBUG, {}, { "addlockoutResetCallback done" })
+ }
+
fun authRequested(uiEvent: FaceAuthUiEvent) {
logBuffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index 0c07c0543246..89e4760615f0 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -85,7 +85,10 @@ constructor(
{
it.scene == Scenes.NotificationsShade || it.scene == Scenes.Shade
},
- SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it.scene == Scenes.QuickSettings },
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
+ {
+ it.scene == Scenes.QuickSettingsShade || it.scene == Scenes.QuickSettings
+ },
SYSUI_STATE_BOUNCER_SHOWING to { it.scene == Scenes.Bouncer },
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
{
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModel.kt
index ba01776aaf8f..f677ec1b31bb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.shade.ui.viewmodel
+package com.android.systemui.notifications.ui.viewmodel
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.SceneKey
@@ -23,6 +23,7 @@ import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index b705a0389300..ea89be61d773 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -21,6 +21,7 @@ import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
import android.content.Context;
import android.os.Handler;
+import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogModule;
import com.android.systemui.dagger.NightDisplayListenerModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -60,6 +61,7 @@ import javax.inject.Named;
*/
@Module(subcomponents = {QSFragmentComponent.class, QSSceneComponent.class},
includes = {
+ BluetoothTileDialogModule.class,
MediaModule.class,
PanelsModule.class,
QSExternalModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index f3852a275209..4fd0df4d3f8f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -186,7 +186,8 @@ open class QSTileViewImpl @JvmOverloads constructor(
private val locInScreen = IntArray(2)
/** Visuo-haptic long-press effects */
- private var haveLongPressPropertiesBeenReset = true
+ var haveLongPressPropertiesBeenReset = true
+ private set
private var paddingForLaunch = Rect()
private var initialLongPressProperties: QSLongPressProperties? = null
private var finalLongPressProperties: QSLongPressProperties? = null
@@ -772,7 +773,11 @@ open class QSTileViewImpl @JvmOverloads constructor(
}
}
- override fun onActivityLaunchAnimationEnd() = resetLongPressEffectProperties()
+ override fun onActivityLaunchAnimationEnd() {
+ if (longPressEffect != null && !haveLongPressPropertiesBeenReset) {
+ resetLongPressEffectProperties()
+ }
+ }
fun prepareForLaunch() {
val startingHeight = initialLongPressProperties?.height?.toInt() ?: 0
@@ -877,8 +882,8 @@ open class QSTileViewImpl @JvmOverloads constructor(
background.updateBounds(
left = 0,
top = 0,
- right = initialLongPressProperties?.width?.toInt() ?: 0,
- bottom = initialLongPressProperties?.height?.toInt() ?: 0,
+ right = initialLongPressProperties?.width?.toInt() ?: measuredWidth,
+ bottom = initialLongPressProperties?.height?.toInt() ?: measuredHeight,
)
changeCornerRadius(resources.getDimensionPixelSize(R.dimen.qs_corner_radius).toFloat())
setAllColors(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileDataInteractor.kt
new file mode 100644
index 000000000000..8c0fd2cd672a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileDataInteractor.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded.domain
+
+import android.os.UserHandle
+import com.android.systemui.accessibility.data.repository.OneHandedModeRepository
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
+import com.android.wm.shell.onehanded.OneHanded
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Observes one handed mode state changes providing the [OneHandedModeTileModel]. */
+class OneHandedModeTileDataInteractor
+@Inject
+constructor(
+ private val oneHandedModeRepository: OneHandedModeRepository,
+) : QSTileDataInteractor<OneHandedModeTileModel> {
+
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<OneHandedModeTileModel> {
+ return oneHandedModeRepository.isEnabled(user).map { OneHandedModeTileModel(it) }
+ }
+ override fun availability(user: UserHandle): Flow<Boolean> =
+ flowOf(OneHanded.sIsSupportOneHandedMode)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt
new file mode 100644
index 000000000000..5cb0e181378b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded.domain
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.accessibility.data.repository.OneHandedModeRepository
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+/** Handles one handed mode tile clicks. */
+class OneHandedModeTileUserActionInteractor
+@Inject
+constructor(
+ private val oneHandedModeRepository: OneHandedModeRepository,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<OneHandedModeTileModel> {
+
+ override suspend fun handleInput(input: QSTileInput<OneHandedModeTileModel>): Unit =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ oneHandedModeRepository.setIsEnabled(
+ !data.isEnabled,
+ user,
+ )
+ }
+ is QSTileUserAction.LongClick -> {
+ qsTileIntentUserActionHandler.handle(
+ action.expandable,
+ Intent(Settings.ACTION_ONE_HANDED_SETTINGS)
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/model/OneHandedModeTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/model/OneHandedModeTileModel.kt
new file mode 100644
index 000000000000..7cebdfe84e2d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/model/OneHandedModeTileModel.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded.domain.model
+
+/**
+ * One handed mode tile model.
+ *
+ * @param isEnabled is true when one handed mode is enabled;
+ */
+@JvmInline value class OneHandedModeTileModel(val isEnabled: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt
new file mode 100644
index 000000000000..9166ed8faacf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded.ui
+
+import android.content.res.Resources
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** Maps [OneHandedModeTileModel] to [QSTileState]. */
+class OneHandedModeTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+) : QSTileDataToStateMapper<OneHandedModeTileModel> {
+
+ override fun map(config: QSTileConfig, data: OneHandedModeTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ val subtitleArray = resources.getStringArray(R.array.tile_states_onehanded)
+ label = resources.getString(R.string.quick_settings_onehanded_label)
+ icon = {
+ Icon.Loaded(
+ resources.getDrawable(
+ com.android.internal.R.drawable.ic_qs_one_handed_mode,
+ theme
+ ),
+ null
+ )
+ }
+ if (data.isEnabled) {
+ activationState = QSTileState.ActivationState.ACTIVE
+ secondaryLabel = subtitleArray[2]
+ } else {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel = subtitleArray[1]
+ }
+ sideViewIcon = QSTileState.SideViewIcon.None
+ contentDescription = label
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt
new file mode 100644
index 000000000000..d48d55dd9918
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.viewmodel
+
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/** Models UI state and handles user input for the Quick Settings Shade scene. */
+@SysUISingleton
+class QuickSettingsShadeSceneViewModel
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ overlayShadeViewModel: OverlayShadeViewModel,
+) {
+ val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
+ overlayShadeViewModel.backgroundScene
+ .map(::destinationScenes)
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = destinationScenes(overlayShadeViewModel.backgroundScene.value),
+ )
+
+ private fun destinationScenes(backgroundScene: SceneKey): Map<UserAction, UserActionResult> {
+ return mapOf(
+ Swipe.Up to backgroundScene,
+ Back to backgroundScene,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 0673dcd5194b..faf2bbc1ba3b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -37,7 +37,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_F
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_TRANSITION;
@@ -118,8 +117,6 @@ import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.sysui.ShellInterface;
-import dagger.Lazy;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -131,6 +128,8 @@ import java.util.function.Supplier;
import javax.inject.Inject;
import javax.inject.Provider;
+import dagger.Lazy;
+
/**
* Class to send information from overview to launcher with a binder.
*/
@@ -701,15 +700,15 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// Listen for tracing state changes
@Override
public void onTracingStateChanged(boolean enabled) {
- mSysUiState.setFlag(SYSUI_STATE_TRACING_ENABLED, enabled)
- .commitUpdate(mContext.getDisplayId());
+ // TODO(b/286509643) Cleanup callers of this; Unused downstream
}
@Override
public void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) {
if (mOverviewProxy != null) {
try {
- if (DesktopModeStatus.isEnabled() && (sysUiState.getFlags()
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)
+ && (sysUiState.getFlags()
& SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index aa8ecfc41fc1..8169dec9ede6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.scene
import com.android.systemui.CoreStartable
+import com.android.systemui.notifications.ui.composable.NotificationsShadeSessionModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -35,6 +36,7 @@ import dagger.multibindings.IntoMap
EmptySceneModule::class,
GoneSceneModule::class,
NotificationsShadeSceneModule::class,
+ NotificationsShadeSessionModule::class,
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
],
@@ -63,7 +65,8 @@ interface KeyguardlessSceneContainerFrameworkModule {
sceneKeys =
listOfNotNull(
Scenes.Gone,
- Scenes.QuickSettings,
+ Scenes.QuickSettings.takeUnless { DualShade.isEnabled },
+ Scenes.QuickSettingsShade.takeIf { DualShade.isEnabled },
Scenes.NotificationsShade.takeIf { DualShade.isEnabled },
Scenes.Shade.takeUnless { DualShade.isEnabled },
),
@@ -73,7 +76,8 @@ interface KeyguardlessSceneContainerFrameworkModule {
Scenes.Gone to 0,
Scenes.NotificationsShade to 1.takeIf { DualShade.isEnabled },
Scenes.Shade to 1.takeUnless { DualShade.isEnabled },
- Scenes.QuickSettings to 2,
+ Scenes.QuickSettingsShade to 2.takeIf { DualShade.isEnabled },
+ Scenes.QuickSettings to 2.takeUnless { DualShade.isEnabled },
)
.filterValues { it != null }
.mapValues { checkNotNull(it.value) }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 551aa124727d..9bd2694f7e82 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -18,6 +18,7 @@ package com.android.systemui.scene
import com.android.systemui.CoreStartable
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlagsModule
+import com.android.systemui.notifications.ui.composable.NotificationsShadeSessionModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -41,7 +42,9 @@ import dagger.multibindings.IntoMap
LockscreenSceneModule::class,
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
+ QuickSettingsShadeSceneModule::class,
NotificationsShadeSceneModule::class,
+ NotificationsShadeSessionModule::class,
],
)
interface SceneContainerFrameworkModule {
@@ -71,7 +74,8 @@ interface SceneContainerFrameworkModule {
Scenes.Communal,
Scenes.Lockscreen,
Scenes.Bouncer,
- Scenes.QuickSettings,
+ Scenes.QuickSettings.takeUnless { DualShade.isEnabled },
+ Scenes.QuickSettingsShade.takeIf { DualShade.isEnabled },
Scenes.NotificationsShade.takeIf { DualShade.isEnabled },
Scenes.Shade.takeUnless { DualShade.isEnabled },
),
@@ -83,7 +87,8 @@ interface SceneContainerFrameworkModule {
Scenes.Communal to 1,
Scenes.NotificationsShade to 2.takeIf { DualShade.isEnabled },
Scenes.Shade to 2.takeUnless { DualShade.isEnabled },
- Scenes.QuickSettings to 3,
+ Scenes.QuickSettingsShade to 3.takeIf { DualShade.isEnabled },
+ Scenes.QuickSettings to 3.takeUnless { DualShade.isEnabled },
Scenes.Bouncer to 4,
)
.filterValues { it != null }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt b/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt
new file mode 100644
index 000000000000..d3e529c9035b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.data.model
+
+import com.android.compose.animation.scene.SceneKey
+
+/** An immutable stack of [SceneKey]s backed by a singly-linked list. */
+sealed interface SceneStack
+
+private data object EmptyStack : SceneStack
+
+private data class StackedNodes(val head: SceneKey, val tail: SceneStack) : SceneStack
+
+/** Returns the scene at the head of the stack, or `null` if empty. O(1) */
+fun SceneStack.peek(): SceneKey? =
+ when (this) {
+ EmptyStack -> null
+ is StackedNodes -> head
+ }
+
+/** Returns a stack with the head removed, or `null` if empty. O(1) */
+fun SceneStack.pop(): SceneStack? =
+ when (this) {
+ EmptyStack -> null
+ is StackedNodes -> tail
+ }
+
+/** Returns a stack with [sceneKey] as the head on top of [this]. O(1) */
+fun SceneStack.push(sceneKey: SceneKey): SceneStack = StackedNodes(sceneKey, this)
+
+/** Returns an iterable that produces all elements in the stack, from head to tail. */
+fun SceneStack.asIterable(): Iterable<SceneKey> = Iterable {
+ iterator {
+ when (this@asIterable) {
+ EmptyStack -> {}
+ is StackedNodes -> {
+ yield(head)
+ yieldAll(tail.asIterable())
+ }
+ }
+ }
+}
+
+/**
+ * Returns a new [SceneStack] containing the given [scenes], ordered such that the first argument is
+ * the head returned from [peek], then the second, and so forth.
+ */
+fun sceneStackOf(vararg scenes: SceneKey): SceneStack {
+ var result: SceneStack = EmptyStack
+ for (sceneKey in scenes.reversed()) {
+ result = result.push(sceneKey)
+ }
+ return result
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index 5748ad459ed6..eabc42b02665 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -87,6 +87,14 @@ constructor(
)
}
+ fun snapToScene(
+ toScene: SceneKey,
+ ) {
+ dataSource.snapToScene(
+ toScene = toScene,
+ )
+ }
+
/** Sets whether the container is visible. */
fun setVisible(isVisible: Boolean) {
_isVisible.value = isVisible
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
index f66d08f781f6..c176ccad7e74 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
@@ -18,13 +18,21 @@ package com.android.systemui.scene.domain.interactor
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.data.model.SceneStack
+import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.data.model.peek
+import com.android.systemui.scene.data.model.pop
+import com.android.systemui.scene.data.model.push
+import com.android.systemui.scene.data.model.sceneStackOf
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.SceneContainerConfig
-import java.util.Stack
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.update
@SysUISingleton
class SceneBackInteractor
@@ -33,7 +41,9 @@ constructor(
private val logger: SceneLogger,
private val sceneContainerConfig: SceneContainerConfig,
) {
- private val _backScene = MutableStateFlow<SceneKey?>(null)
+ private val _backStack = MutableStateFlow(sceneStackOf())
+ val backStack: StateFlow<SceneStack> = _backStack.asStateFlow()
+
/**
* The scene to navigate to when the user triggers back navigation.
*
@@ -44,30 +54,30 @@ constructor(
* illegal state to have scene implementation map to itself in its destination scene flow. Thus,
* scene implementations might wish to filter their own scene key out before using this.
*/
- val backScene: StateFlow<SceneKey?> = _backScene.asStateFlow()
-
- private val backStack = Stack<SceneKey>()
+ val backScene: Flow<SceneKey?> = backStack.map { it.peek() }
fun onSceneChange(from: SceneKey, to: SceneKey) {
check(from != to) { "from == to, from=${from.debugName}, to=${to.debugName}" }
when (stackOperation(from, to)) {
Clear -> {
- backStack.clear()
+ _backStack.value = sceneStackOf()
}
Push -> {
- backStack.push(from)
+ _backStack.update { s -> s.push(from) }
}
Pop -> {
- check(backStack.isNotEmpty()) { "Cannot pop ${from.debugName} when stack is empty" }
- val popped = backStack.pop()
- check(to == popped) {
- "Expected to pop ${to.debugName} but instead popped ${popped.debugName}"
+ _backStack.update { s ->
+ checkNotNull(s.pop()) { "Cannot pop ${from.debugName} when stack is empty" }
+ .also {
+ val popped = s.peek()
+ check(popped == to) {
+ "Expected to pop ${to.debugName} but instead popped ${popped?.debugName}"
+ }
+ }
}
}
}
-
- logger.logSceneBackStack(backStack)
- _backScene.value = peek()
+ logger.logSceneBackStack(backStack.value.asIterable())
}
private fun stackOperation(from: SceneKey, to: SceneKey): StackOperation {
@@ -92,14 +102,6 @@ constructor(
}
}
- private fun peek(): SceneKey? {
- return if (backStack.isNotEmpty()) {
- backStack.peek()
- } else {
- null
- }
- }
-
private sealed interface StackOperation
private data object Clear : StackOperation
private data object Push : StackOperation
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
index ace449136fad..6bcd92316106 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
@@ -127,6 +127,7 @@ constructor(
Scenes.Lockscreen -> true
Scenes.NotificationsShade -> false
Scenes.QuickSettings -> false
+ Scenes.QuickSettingsShade -> false
Scenes.Shade -> false
else -> error("SceneKey \"$this\" doesn't have a mapping for canBeOccluded!")
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 93cef61d9dae..08efe39d7674 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -162,19 +162,45 @@ constructor(
loggingReason: String,
transitionKey: TransitionKey? = null,
) {
- if (!repository.allSceneKeys().contains(toScene)) {
+ val currentSceneKey = currentScene.value
+ if (
+ !validateSceneChange(
+ from = currentSceneKey,
+ to = toScene,
+ loggingReason = loggingReason,
+ )
+ ) {
return
}
- check(
- toScene != Scenes.Gone || deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked
- ) {
- "Cannot change to the Gone scene while the device is locked. Logging reason for scene" +
- " change was: $loggingReason"
- }
+ logger.logSceneChangeRequested(
+ from = currentSceneKey,
+ to = toScene,
+ reason = loggingReason,
+ isInstant = false,
+ )
+
+ repository.changeScene(toScene, transitionKey)
+ }
+ /**
+ * Requests a scene change to the given scene.
+ *
+ * The change is instantaneous and not animated; it will be observable in the next frame and
+ * there will be no transition animation.
+ */
+ fun snapToScene(
+ toScene: SceneKey,
+ loggingReason: String,
+ ) {
val currentSceneKey = currentScene.value
- if (currentSceneKey == toScene) {
+ if (
+ !validateSceneChange(
+ from = currentSceneKey,
+ to = toScene,
+ loggingReason = loggingReason,
+ )
+ ) {
return
}
@@ -182,9 +208,10 @@ constructor(
from = currentSceneKey,
to = toScene,
reason = loggingReason,
+ isInstant = true,
)
- repository.changeScene(toScene, transitionKey)
+ repository.snapToScene(toScene)
}
/**
@@ -249,4 +276,32 @@ constructor(
): Boolean {
return raw || isRemoteUserInteractionOngoing
}
+
+ /**
+ * Validates that the given scene change is allowed.
+ *
+ * Will throw a runtime exception for illegal states (for example, attempting to change to a
+ * scene that's not part of the current scene framework configuration).
+ *
+ * @param from The current scene being transitioned away from
+ * @param to The desired destination scene to transition to
+ * @param loggingReason The reason why the transition is requested, for logging purposes
+ * @return `true` if the scene change is valid; `false` if it shouldn't happen
+ */
+ private fun validateSceneChange(
+ from: SceneKey,
+ to: SceneKey,
+ loggingReason: String,
+ ): Boolean {
+ if (!repository.allSceneKeys().contains(to)) {
+ return false
+ }
+
+ check(to != Scenes.Gone || deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked) {
+ "Cannot change to the Gone scene while the device is locked. Logging reason for scene" +
+ " change was: $loggingReason"
+ }
+
+ return from != to
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
index de3b87aebcd3..9c2b992c0de6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
@@ -78,13 +78,16 @@ constructor(
is ObservableTransitionState.Idle ->
state.currentScene == Scenes.Shade ||
state.currentScene == Scenes.NotificationsShade ||
+ state.currentScene == Scenes.QuickSettingsShade ||
state.currentScene == Scenes.Lockscreen
is ObservableTransitionState.Transition ->
state.toScene == Scenes.Shade ||
state.toScene == Scenes.NotificationsShade ||
+ state.toScene == Scenes.QuickSettingsShade ||
state.toScene == Scenes.Lockscreen ||
state.fromScene == Scenes.Shade ||
state.fromScene == Scenes.NotificationsShade ||
+ state.fromScene == Scenes.QuickSettingsShade ||
state.fromScene == Scenes.Lockscreen
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 9e5796449976..4a6427794def 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -45,9 +45,11 @@ import com.android.systemui.model.updateFlags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.data.model.asIterable
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.session.shared.SessionStorage
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.Scenes
@@ -116,6 +118,7 @@ constructor(
private val shadeInteractor: ShadeInteractor,
private val uiEventLogger: UiEventLogger,
private val sceneBackInteractor: SceneBackInteractor,
+ private val shadeSessionStorage: SessionStorage,
) : CoreStartable {
private val centralSurfaces: CentralSurfaces?
get() = centralSurfacesOptLazy.get().getOrNull()
@@ -132,6 +135,7 @@ constructor(
handleBouncerOverscroll()
hydrateWindowController()
hydrateBackStack()
+ resetShadeSessions()
} else {
sceneLogger.logFrameworkEnabled(
isEnabled = false,
@@ -150,6 +154,20 @@ constructor(
}
}
+ private fun resetShadeSessions() {
+ applicationScope.launch {
+ sceneBackInteractor.backStack
+ // We are in a session if either Shade or QuickSettings is on the back stack
+ .map { backStack ->
+ backStack.asIterable().any { it == Scenes.Shade || it == Scenes.QuickSettings }
+ }
+ .distinctUntilChanged()
+ // Once a session has ended, clear the session storage.
+ .filter { inSession -> !inSession }
+ .collect { shadeSessionStorage.clear() }
+ }
+ }
+
/** Updates the visibility of the scene container. */
private fun hydrateVisibility() {
applicationScope.launch {
@@ -307,8 +325,7 @@ constructor(
Scenes.Gone to "device was unlocked in Bouncer scene"
} else {
val prevScene = previousScene.value
- (prevScene
- ?: Scenes.Gone) to
+ (prevScene ?: Scenes.Gone) to
"device was unlocked in Bouncer scene, from sceneKey=$prevScene"
}
isOnLockscreen ->
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index 5ebdd8698656..9d6720b02052 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -20,7 +20,6 @@ import com.android.compose.animation.scene.SceneKey
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.SceneFrameworkLog
-import java.util.Stack
import javax.inject.Inject
class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: LogBuffer) {
@@ -47,6 +46,7 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
from: SceneKey,
to: SceneKey,
reason: String,
+ isInstant: Boolean,
) {
logBuffer.log(
tag = TAG,
@@ -55,8 +55,17 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
str1 = from.toString()
str2 = to.toString()
str3 = reason
+ bool1 = isInstant
+ },
+ messagePrinter = {
+ buildString {
+ append("Scene change requested: $str1 → $str2")
+ if (isInstant) {
+ append(" (instant)")
+ }
+ append(", reason: $str3")
+ }
},
- messagePrinter = { "Scene change requested: $str1 → $str2, reason: $str3" },
)
}
@@ -116,7 +125,7 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
)
}
- fun logSceneBackStack(backStack: Stack<SceneKey>) {
+ fun logSceneBackStack(backStack: Iterable<SceneKey>) {
logBuffer.log(
tag = TAG,
level = LogLevel.INFO,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
index 0e078d5d8064..034da25f1a45 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
@@ -40,4 +40,11 @@ interface SceneDataSource {
toScene: SceneKey,
transitionKey: TransitionKey? = null,
)
+
+ /**
+ * Asks for an instant scene switch to [toScene], without an animated transition of any kind.
+ */
+ fun snapToScene(
+ toScene: SceneKey,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
index 2fbcba977a91..43c3635f32fc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
@@ -56,6 +56,12 @@ class SceneDataSourceDelegator(
)
}
+ override fun snapToScene(toScene: SceneKey) {
+ delegateMutable.value.snapToScene(
+ toScene = toScene,
+ )
+ }
+
/**
* Binds the current, dependency injection provided [SceneDataSource] to the given object.
*
@@ -77,5 +83,7 @@ class SceneDataSourceDelegator(
MutableStateFlow(initialSceneKey).asStateFlow()
override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) = Unit
+
+ override fun snapToScene(toScene: SceneKey) = Unit
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
index 08f1be908afd..6d139da99345 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
@@ -47,19 +47,45 @@ object Scenes {
* overlay UI.
*
* It's used only in the dual shade configuration, where there are two separate shades: one for
- * notifications (this scene) and another for quick settings (where a separate scene is used).
+ * notifications (this scene) and another for [QuickSettingsShade].
*
* It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) and for the "split" shade configuration (on
+ * swipe down again the to expand quick settings) or in the "split" shade configuration (on
* large screens or unfolded foldables, where notifications and quick settings are shown
* side-by-side in their own columns).
*/
@JvmField val NotificationsShade = SceneKey("notifications_shade")
- /** The quick settings scene shows the quick setting tiles. */
+ /**
+ * The quick settings scene shows the quick setting tiles.
+ *
+ * This scene is used for single/accordion configuration (swipe down once to reveal the shade,
+ * swipe down again the to expand quick settings).
+ *
+ * For the "split" shade configuration (on large screens or unfolded foldables, where
+ * notifications and quick settings are shown side-by-side in their own columns), the [Shade]
+ * scene is used].
+ *
+ * For the dual shade configuration, where there are two separate shades: one for notifications
+ * and one for quick settings, [NotificationsShade] and [QuickSettingsShade] scenes are used
+ * respectively.
+ */
@JvmField val QuickSettings = SceneKey("quick_settings")
/**
+ * The quick settings shade scene shows the quick setting tiles as an overlay UI.
+ *
+ * It's used only in the dual shade configuration, where there are two separate shades: one for
+ * quick settings (this scene) and another for [NotificationsShade].
+ *
+ * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
+ * swipe down again the to expand quick settings) or in the "split" shade configuration (on
+ * large screens or unfolded foldables, where notifications and quick settings are shown
+ * side-by-side in their own columns).
+ */
+ @JvmField val QuickSettingsShade = SceneKey("quick_settings_shade")
+
+ /**
* The shade is the scene that shows a scrollable list of notifications and the minimized
* version of quick settings (AKA "quick quick settings" or "QQS").
*
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
index e4435ccd205c..b0af7f9ce072 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
@@ -60,6 +60,16 @@ constructor(
)] = UserActionResult(Scenes.QuickSettings)
}
+ // TODO(b/338577208): Remove this once we add Dual Shade invocation zones.
+ if (shadeMode is ShadeMode.Dual) {
+ this[
+ Swipe(
+ pointerCount = 2,
+ fromSource = Edge.Top,
+ direction = SwipeDirection.Down,
+ )] = UserActionResult(Scenes.QuickSettingsShade)
+ }
+
this[Swipe(direction = SwipeDirection.Down)] =
UserActionResult(
if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 7fbede475e69..09c80b09a388 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -127,6 +127,7 @@ constructor(
Scenes.NotificationsShade -> Classifier.NOTIFICATION_DRAG_DOWN
Scenes.Shade -> Classifier.NOTIFICATION_DRAG_DOWN
Scenes.QuickSettings -> Classifier.QUICK_SETTINGS
+ Scenes.QuickSettingsShade -> Classifier.QUICK_SETTINGS
else -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
index 07e143a34319..ef1d87da47be 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
@@ -87,7 +87,8 @@ constructor(
AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_edit),
context.resources.getString(R.string.screenshot_edit_label),
context.resources.getString(R.string.screenshot_edit_description),
- )
+ ),
+ showDuringEntrance = true,
) {
debugLog(LogConfig.DEBUG_ACTIONS) { "Edit tapped" }
uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString)
@@ -105,7 +106,8 @@ constructor(
AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_share),
context.resources.getString(R.string.screenshot_share_label),
context.resources.getString(R.string.screenshot_share_description),
- )
+ ),
+ showDuringEntrance = true,
) {
debugLog(LogConfig.DEBUG_ACTIONS) { "Share tapped" }
uiEventLogger.log(SCREENSHOT_SHARE_TAPPED, 0, request.packageNameString)
@@ -125,7 +127,8 @@ constructor(
AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_scroll),
context.resources.getString(R.string.screenshot_scroll_label),
context.resources.getString(R.string.screenshot_scroll_label),
- )
+ ),
+ showDuringEntrance = true,
) {
onClick.run()
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 494fc9b8c683..bd90de230d5f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -47,7 +47,6 @@ import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Process;
import android.os.UserHandle;
@@ -208,8 +207,7 @@ public class ScreenshotController {
@Nullable
private final ScreenshotSoundController mScreenshotSoundController;
private final PhoneWindow mWindow;
- private final DisplayManager mDisplayManager;
- private final int mDisplayId;
+ private final Display mDisplay;
private final ScrollCaptureExecutor mScrollCaptureExecutor;
private final ScreenshotNotificationSmartActionsProvider
mScreenshotNotificationSmartActionsProvider;
@@ -249,7 +247,6 @@ public class ScreenshotController {
@AssistedInject
ScreenshotController(
Context context,
- DisplayManager displayManager,
WindowManager windowManager,
FeatureFlags flags,
ScreenshotViewProxy.Factory viewProxyFactory,
@@ -271,12 +268,13 @@ public class ScreenshotController {
AssistContentRequester assistContentRequester,
MessageContainerController messageContainerController,
Provider<ScreenshotSoundController> screenshotSoundController,
- @Assisted int displayId,
+ @Assisted Display display,
@Assisted boolean showUIOnExternalDisplay
) {
mScreenshotSmartActions = screenshotSmartActions;
mActionsProviderFactory = actionsProviderFactory;
- mNotificationsController = screenshotNotificationsControllerFactory.create(displayId);
+ mNotificationsController = screenshotNotificationsControllerFactory.create(
+ display.getDisplayId());
mUiEventLogger = uiEventLogger;
mImageExporter = imageExporter;
mImageCapture = imageCapture;
@@ -290,11 +288,9 @@ public class ScreenshotController {
mScreenshotHandler = timeoutHandler;
mScreenshotHandler.setDefaultTimeoutMillis(SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS);
-
- mDisplayId = displayId;
- mDisplayManager = displayManager;
+ mDisplay = display;
mWindowManager = windowManager;
- final Context displayContext = context.createDisplayContext(getDisplay());
+ final Context displayContext = context.createDisplayContext(display);
mContext = (WindowContext) displayContext.createWindowContext(TYPE_SCREENSHOT, null);
mFlags = flags;
mActionIntentExecutor = actionIntentExecutor;
@@ -302,7 +298,7 @@ public class ScreenshotController {
mMessageContainerController = messageContainerController;
mAssistContentRequester = assistContentRequester;
- mViewProxy = viewProxyFactory.getProxy(mContext, mDisplayId);
+ mViewProxy = viewProxyFactory.getProxy(mContext, mDisplay.getDisplayId());
mScreenshotHandler.setOnTimeoutRunnable(() -> {
if (DEBUG_UI) {
@@ -328,7 +324,7 @@ public class ScreenshotController {
});
// Sound is only reproduced from the controller of the default display.
- if (displayId == Display.DEFAULT_DISPLAY) {
+ if (mDisplay.getDisplayId() == Display.DEFAULT_DISPLAY) {
mScreenshotSoundController = screenshotSoundController.get();
} else {
mScreenshotSoundController = null;
@@ -356,7 +352,7 @@ public class ScreenshotController {
if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN
&& screenshot.getBitmap() == null) {
Rect bounds = getFullScreenRect();
- screenshot.setBitmap(mImageCapture.captureDisplay(mDisplayId, bounds));
+ screenshot.setBitmap(mImageCapture.captureDisplay(mDisplay.getDisplayId(), bounds));
screenshot.setScreenBounds(bounds);
}
@@ -459,7 +455,7 @@ public class ScreenshotController {
}
private boolean shouldShowUi() {
- return mDisplayId == Display.DEFAULT_DISPLAY || mShowUIOnExternalDisplay;
+ return mDisplay.getDisplayId() == Display.DEFAULT_DISPLAY || mShowUIOnExternalDisplay;
}
void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) {
@@ -618,7 +614,7 @@ public class ScreenshotController {
private void requestScrollCapture(UserHandle owner) {
mScrollCaptureExecutor.requestScrollCapture(
- mDisplayId,
+ mDisplay.getDisplayId(),
mWindow.getDecorView().getWindowToken(),
(response) -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION,
@@ -641,7 +637,8 @@ public class ScreenshotController {
}
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED, 0,
response.getPackageName());
- Bitmap newScreenshot = mImageCapture.captureDisplay(mDisplayId, getFullScreenRect());
+ Bitmap newScreenshot = mImageCapture.captureDisplay(mDisplay.getDisplayId(),
+ getFullScreenRect());
if (newScreenshot == null) {
Log.e(TAG, "Failed to capture current screenshot for scroll transition!");
return;
@@ -819,7 +816,8 @@ public class ScreenshotController {
private void saveScreenshotInBackground(
ScreenshotData screenshot, UUID requestId, Consumer<Uri> finisher) {
ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor,
- requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(), mDisplayId);
+ requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(),
+ mDisplay.getDisplayId());
future.addListener(() -> {
try {
ImageExporter.Result result = future.get();
@@ -861,7 +859,7 @@ public class ScreenshotController {
data.mActionsReadyListener = actionsReadyListener;
data.mQuickShareActionsReadyListener = quickShareActionsReadyListener;
data.owner = owner;
- data.displayId = mDisplayId;
+ data.displayId = mDisplay.getDisplayId();
if (mSaveInBgTask != null) {
// just log success/failure for the pre-existing screenshot
@@ -986,13 +984,9 @@ public class ScreenshotController {
}
}
- private Display getDisplay() {
- return mDisplayManager.getDisplay(mDisplayId);
- }
-
private Rect getFullScreenRect() {
DisplayMetrics displayMetrics = new DisplayMetrics();
- getDisplay().getRealMetrics(displayMetrics);
+ mDisplay.getRealMetrics(displayMetrics);
return new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
}
@@ -1026,12 +1020,12 @@ public class ScreenshotController {
@AssistedFactory
public interface Factory {
/**
- * Creates an instance of the controller for that specific displayId.
+ * Creates an instance of the controller for that specific display.
*
- * @param displayId: display to capture
- * @param showUIOnExternalDisplay: Whether the UI should be shown if this is an external
- * display.
+ * @param display display to capture
+ * @param showUIOnExternalDisplay Whether the UI should be shown if this is an external
+ * display.
*/
- ScreenshotController create(int displayId, boolean showUIOnExternalDisplay);
+ ScreenshotController create(Display display, boolean showUIOnExternalDisplay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
index 9b5e71827ead..412b08905ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
@@ -45,6 +45,7 @@ import com.android.systemui.screenshot.scroll.ScrollCaptureController
import com.android.systemui.screenshot.ui.ScreenshotAnimationController
import com.android.systemui.screenshot.ui.ScreenshotShelfView
import com.android.systemui.screenshot.ui.binder.ScreenshotShelfViewBinder
+import com.android.systemui.screenshot.ui.viewmodel.AnimationState
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -119,12 +120,19 @@ constructor(
override fun updateOrientation(insets: WindowInsets) {}
override fun createScreenshotDropInAnimation(screenRect: Rect, showFlash: Boolean): Animator {
- val entrance = animationController.getEntranceAnimation(screenRect, showFlash)
- entrance.doOnStart { thumbnailObserver.onEntranceStarted() }
+ val entrance =
+ animationController.getEntranceAnimation(screenRect, showFlash) {
+ viewModel.setAnimationState(AnimationState.ENTRANCE_REVEAL)
+ }
+ entrance.doOnStart {
+ thumbnailObserver.onEntranceStarted()
+ viewModel.setAnimationState(AnimationState.ENTRANCE_STARTED)
+ }
entrance.doOnEnd {
// reset the timeout when animation finishes
callbacks?.onUserInteraction()
thumbnailObserver.onEntranceComplete()
+ viewModel.setAnimationState(AnimationState.ENTRANCE_COMPLETE)
}
return entrance
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
index e56a4f45d7aa..40d709d0ab25 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
@@ -68,11 +68,13 @@ constructor(
onSaved: (Uri?) -> Unit,
requestCallback: RequestCallback
) {
- val displayIds = getDisplaysToScreenshot(screenshotRequest.type)
+ val displays = getDisplaysToScreenshot(screenshotRequest.type)
val resultCallbackWrapper = MultiResultCallbackWrapper(requestCallback)
- displayIds.forEach { displayId: Int ->
+ displays.forEach { display ->
+ val displayId = display.displayId
Log.d(TAG, "Executing screenshot for display $displayId")
dispatchToController(
+ display = display,
rawScreenshotData = ScreenshotData.fromRequest(screenshotRequest, displayId),
onSaved =
if (displayId == Display.DEFAULT_DISPLAY) {
@@ -85,6 +87,7 @@ constructor(
/** All logging should be triggered only by this method. */
private suspend fun dispatchToController(
+ display: Display,
rawScreenshotData: ScreenshotData,
onSaved: (Uri?) -> Unit,
callback: RequestCallback
@@ -104,8 +107,7 @@ constructor(
logScreenshotRequested(screenshotData)
Log.d(TAG, "Screenshot request: $screenshotData")
try {
- getScreenshotController(screenshotData.displayId)
- .handleScreenshot(screenshotData, onSaved, callback)
+ getScreenshotController(display).handleScreenshot(screenshotData, onSaved, callback)
} catch (e: IllegalStateException) {
Log.e(TAG, "Error while ScreenshotController was handling ScreenshotData!", e)
onFailedScreenshotRequest(screenshotData, callback)
@@ -135,12 +137,13 @@ constructor(
callback.reportError()
}
- private suspend fun getDisplaysToScreenshot(requestType: Int): List<Int> {
+ private suspend fun getDisplaysToScreenshot(requestType: Int): List<Display> {
+ val allDisplays = displays.first()
return if (requestType == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
// If this is a provided image, let's show the UI on the default display only.
- listOf(Display.DEFAULT_DISPLAY)
+ allDisplays.filter { it.displayId == Display.DEFAULT_DISPLAY }
} else {
- displays.first().filter { it.type in ALLOWED_DISPLAY_TYPES }.map { it.displayId }
+ allDisplays.filter { it.type in ALLOWED_DISPLAY_TYPES }
}
}
@@ -170,9 +173,9 @@ constructor(
screenshotControllers.clear()
}
- private fun getScreenshotController(id: Int): ScreenshotController {
- return screenshotControllers.computeIfAbsent(id) {
- screenshotControllerFactory.create(id, /* showUIOnExternalDisplay= */ false)
+ private fun getScreenshotController(display: Display): ScreenshotController {
+ return screenshotControllers.computeIfAbsent(display.displayId) {
+ screenshotControllerFactory.create(display, /* showUIOnExternalDisplay= */ false)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
index da268300e8c4..06e88f46c5f1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
@@ -47,7 +47,11 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
view.requireViewById(R.id.screenshot_dismiss_button)
)
- fun getEntranceAnimation(bounds: Rect, showFlash: Boolean): Animator {
+ fun getEntranceAnimation(
+ bounds: Rect,
+ showFlash: Boolean,
+ onRevealMilestone: () -> Unit
+ ): Animator {
val entranceAnimation = AnimatorSet()
val previewAnimator = getPreviewAnimator(bounds)
@@ -70,7 +74,19 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
entranceAnimation.doOnStart { screenshotPreview.visibility = View.INVISIBLE }
}
- entranceAnimation.play(getActionsAnimator()).with(previewAnimator)
+ val actionsAnimator = getActionsAnimator()
+ entranceAnimation.play(actionsAnimator).with(previewAnimator)
+
+ // This isn't actually animating anything but is basically a timer for the first 200ms of
+ // the entrance animation. Using an animator here ensures that this is scaled if we change
+ // animator duration scales.
+ val revealMilestoneAnimator =
+ ValueAnimator.ofFloat(0f).apply {
+ duration = 0
+ startDelay = ACTION_REVEAL_DELAY_MS
+ doOnEnd { onRevealMilestone() }
+ }
+ entranceAnimation.play(revealMilestoneAnimator).with(actionsAnimator)
val fadeInAnimator = ValueAnimator.ofFloat(0f, 1f)
fadeInAnimator.addUpdateListener {
@@ -198,5 +214,6 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
private const val FLASH_OUT_DURATION_MS: Long = 217
private const val PREVIEW_X_ANIMATION_DURATION_MS: Long = 234
private const val PREVIEW_Y_ANIMATION_DURATION_MS: Long = 500
+ private const val ACTION_REVEAL_DELAY_MS: Long = 200
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/TransitioningIconDrawable.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/TransitioningIconDrawable.kt
new file mode 100644
index 000000000000..0bc280c6c1e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/TransitioningIconDrawable.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot.ui
+
+import android.animation.ValueAnimator
+import android.content.res.ColorStateList
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.drawable.Drawable
+import androidx.core.animation.doOnEnd
+import java.util.Objects
+
+/** */
+class TransitioningIconDrawable : Drawable() {
+ // The drawable for the current icon of this view. During icon transitions, this is the one
+ // being animated out.
+ private var drawable: Drawable? = null
+
+ // The incoming new icon. Only populated during transition animations (when drawable is also
+ // non-null).
+ private var enteringDrawable: Drawable? = null
+ private var colorFilter: ColorFilter? = null
+ private var tint: ColorStateList? = null
+ private var alpha = 255
+
+ private var transitionAnimator =
+ ValueAnimator.ofFloat(0f, 1f).also { it.doOnEnd { onTransitionComplete() } }
+
+ /**
+ * Set the drawable to be displayed, potentially animating the transition from one icon to the
+ * next.
+ */
+ fun setIcon(incomingDrawable: Drawable?) {
+ if (Objects.equals(drawable, incomingDrawable) && !transitionAnimator.isRunning) {
+ return
+ }
+
+ incomingDrawable?.colorFilter = colorFilter
+ incomingDrawable?.setTintList(tint)
+
+ if (drawable == null) {
+ // No existing icon drawn, just show the new one without a transition
+ drawable = incomingDrawable
+ invalidateSelf()
+ return
+ }
+
+ if (enteringDrawable != null) {
+ // There's already an entrance animation happening, just update the entering icon, not
+ // maintaining a queue or anything.
+ enteringDrawable = incomingDrawable
+ return
+ }
+
+ // There was already an icon, need to animate between icons.
+ enteringDrawable = incomingDrawable
+ transitionAnimator.setCurrentFraction(0f)
+ transitionAnimator.start()
+ invalidateSelf()
+ }
+
+ override fun draw(canvas: Canvas) {
+ // Scale the old one down, scale the new one up.
+ drawable?.let {
+ val scale =
+ if (transitionAnimator.isRunning) {
+ 1f - transitionAnimator.animatedFraction
+ } else {
+ 1f
+ }
+ drawScaledDrawable(it, canvas, scale)
+ }
+ enteringDrawable?.let {
+ val scale = transitionAnimator.animatedFraction
+ drawScaledDrawable(it, canvas, scale)
+ }
+
+ if (transitionAnimator.isRunning) {
+ invalidateSelf()
+ }
+ }
+
+ private fun drawScaledDrawable(drawable: Drawable, canvas: Canvas, scale: Float) {
+ drawable.bounds = getBounds()
+ canvas.save()
+ canvas.scale(
+ scale,
+ scale,
+ (drawable.intrinsicWidth / 2).toFloat(),
+ (drawable.intrinsicHeight / 2).toFloat()
+ )
+ drawable.draw(canvas)
+ canvas.restore()
+ }
+
+ private fun onTransitionComplete() {
+ drawable = enteringDrawable
+ enteringDrawable = null
+ invalidateSelf()
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ super.setTintList(tint)
+ drawable?.setTintList(tint)
+ enteringDrawable?.setTintList(tint)
+ this.tint = tint
+ }
+
+ override fun setAlpha(alpha: Int) {
+ this.alpha = alpha
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ this.colorFilter = colorFilter
+ drawable?.colorFilter = colorFilter
+ enteringDrawable?.colorFilter = colorFilter
+ }
+
+ override fun getOpacity(): Int = alpha
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
index 3c5a0ec107f8..750bd530d9b2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
@@ -21,6 +21,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.android.systemui.res.R
+import com.android.systemui.screenshot.ui.TransitioningIconDrawable
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
object ActionButtonViewBinder {
@@ -28,7 +29,13 @@ object ActionButtonViewBinder {
fun bind(view: View, viewModel: ActionButtonViewModel) {
val iconView = view.requireViewById<ImageView>(R.id.overlay_action_chip_icon)
val textView = view.requireViewById<TextView>(R.id.overlay_action_chip_text)
- iconView.setImageDrawable(viewModel.appearance.icon)
+ if (iconView.drawable == null) {
+ iconView.setImageDrawable(TransitioningIconDrawable())
+ }
+ val drawable = iconView.drawable as? TransitioningIconDrawable
+ // Note we never re-bind a view to a different ActionButtonViewModel, different view
+ // models would remove/create separate views.
+ drawable?.setIcon(viewModel.appearance.icon)
textView.text = viewModel.appearance.label
setMargins(iconView, textView, viewModel.appearance.label?.isNotEmpty() ?: false)
if (viewModel.onClicked != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
index bc35e6b17345..43c0107c12d5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
@@ -31,6 +31,8 @@ import com.android.systemui.res.R
import com.android.systemui.screenshot.ScreenshotEvent
import com.android.systemui.screenshot.ui.ScreenshotShelfView
import com.android.systemui.screenshot.ui.SwipeGestureListener
+import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
+import com.android.systemui.screenshot.ui.viewmodel.AnimationState
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import com.android.systemui.util.children
import kotlinx.coroutines.Dispatchers
@@ -59,7 +61,6 @@ object ScreenshotShelfViewBinder {
val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border)
previewView.clipToOutline = true
previewViewBlur.clipToOutline = true
- val actionsContainer: LinearLayout = view.requireViewById(R.id.screenshot_actions)
val dismissButton = view.requireViewById<View>(R.id.screenshot_dismiss_button)
dismissButton.visibility = if (viewModel.showDismissButton) View.VISIBLE else View.GONE
dismissButton.setOnClickListener {
@@ -90,47 +91,72 @@ object ScreenshotShelfViewBinder {
}
launch {
viewModel.actions.collect { actions ->
- val visibleActions = actions.filter { it.visible }
+ updateActions(
+ actions,
+ viewModel.animationState.value,
+ view,
+ layoutInflater
+ )
+ }
+ }
+ launch {
+ viewModel.animationState.collect { animationState ->
+ updateActions(
+ viewModel.actions.value,
+ animationState,
+ view,
+ layoutInflater
+ )
+ }
+ }
+ }
+ }
+ }
+ }
- if (visibleActions.isNotEmpty()) {
- view
- .requireViewById<View>(R.id.actions_container_background)
- .visibility = View.VISIBLE
- }
+ private fun updateActions(
+ actions: List<ActionButtonViewModel>,
+ animationState: AnimationState,
+ view: ScreenshotShelfView,
+ layoutInflater: LayoutInflater
+ ) {
+ val actionsContainer: LinearLayout = view.requireViewById(R.id.screenshot_actions)
+ val visibleActions =
+ actions.filter {
+ it.visible &&
+ (animationState == AnimationState.ENTRANCE_COMPLETE ||
+ animationState == AnimationState.ENTRANCE_REVEAL ||
+ it.showDuringEntrance)
+ }
- // Remove any buttons not in the new list, then do another pass to add
- // any new actions and update any that are already there.
- // This assumes that actions can never change order and that each action
- // ID is unique.
- val newIds = visibleActions.map { it.id }
+ if (visibleActions.isNotEmpty()) {
+ view.requireViewById<View>(R.id.actions_container_background).visibility = View.VISIBLE
+ }
- for (child in actionsContainer.children.toList()) {
- if (child.tag !in newIds) {
- actionsContainer.removeView(child)
- }
- }
+ // Remove any buttons not in the new list, then do another pass to add
+ // any new actions and update any that are already there.
+ // This assumes that actions can never change order and that each action
+ // ID is unique.
+ val newIds = visibleActions.map { it.id }
- for ((index, action) in visibleActions.withIndex()) {
- val currentView: View? = actionsContainer.getChildAt(index)
- if (action.id == currentView?.tag) {
- // Same ID, update the display
- ActionButtonViewBinder.bind(currentView, action)
- } else {
- // Different ID. Removals have already happened so this must
- // mean that the new action must be inserted here.
- val actionButton =
- layoutInflater.inflate(
- R.layout.shelf_action_chip,
- actionsContainer,
- false
- )
- actionsContainer.addView(actionButton, index)
- ActionButtonViewBinder.bind(actionButton, action)
- }
- }
- }
- }
- }
+ for (child in actionsContainer.children.toList()) {
+ if (child.tag !in newIds) {
+ actionsContainer.removeView(child)
+ }
+ }
+
+ for ((index, action) in visibleActions.withIndex()) {
+ val currentView: View? = actionsContainer.getChildAt(index)
+ if (action.id == currentView?.tag) {
+ // Same ID, update the display
+ ActionButtonViewBinder.bind(currentView, action)
+ } else {
+ // Different ID. Removals have already happened so this must
+ // mean that the new action must be inserted here.
+ val actionButton =
+ layoutInflater.inflate(R.layout.shelf_action_chip, actionsContainer, false)
+ actionsContainer.addView(actionButton, index)
+ ActionButtonViewBinder.bind(actionButton, action)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt
index c5fa8db953fa..364ab7624b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt
@@ -20,6 +20,7 @@ data class ActionButtonViewModel(
val appearance: ActionButtonAppearance,
val id: Int,
val visible: Boolean,
+ val showDuringEntrance: Boolean,
val onClicked: (() -> Unit)?,
) {
companion object {
@@ -29,7 +30,14 @@ data class ActionButtonViewModel(
fun withNextId(
appearance: ActionButtonAppearance,
+ showDuringEntrance: Boolean,
onClicked: (() -> Unit)?
- ): ActionButtonViewModel = ActionButtonViewModel(appearance, getId(), true, onClicked)
+ ): ActionButtonViewModel =
+ ActionButtonViewModel(appearance, getId(), true, showDuringEntrance, onClicked)
+
+ fun withNextId(
+ appearance: ActionButtonAppearance,
+ onClicked: (() -> Unit)?
+ ): ActionButtonViewModel = withNextId(appearance, showDuringEntrance = true, onClicked)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
index f67ad402a738..5f36f73f2135 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
@@ -29,6 +29,9 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
val previewAction: StateFlow<(() -> Unit)?> = _previewAction
private val _actions = MutableStateFlow(emptyList<ActionButtonViewModel>())
val actions: StateFlow<List<ActionButtonViewModel>> = _actions
+ private val _animationState = MutableStateFlow(AnimationState.NOT_STARTED)
+ val animationState: StateFlow<AnimationState> = _animationState
+
val showDismissButton: Boolean
get() = accessibilityManager.isEnabled
@@ -40,9 +43,14 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
_previewAction.value = onClick
}
- fun addAction(actionAppearance: ActionButtonAppearance, onClicked: (() -> Unit)): Int {
+ fun addAction(
+ actionAppearance: ActionButtonAppearance,
+ showDuringEntrance: Boolean,
+ onClicked: (() -> Unit)
+ ): Int {
val actionList = _actions.value.toMutableList()
- val action = ActionButtonViewModel.withNextId(actionAppearance, onClicked)
+ val action =
+ ActionButtonViewModel.withNextId(actionAppearance, showDuringEntrance, onClicked)
actionList.add(action)
_actions.value = actionList
return action.id
@@ -57,6 +65,7 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
actionList[index].appearance,
actionId,
visible,
+ actionList[index].showDuringEntrance,
actionList[index].onClicked
)
_actions.value = actionList
@@ -74,6 +83,7 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
appearance,
actionId,
actionList[index].visible,
+ actionList[index].showDuringEntrance,
actionList[index].onClicked
)
_actions.value = actionList
@@ -92,13 +102,26 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager
}
}
+ // TODO: this should be handled entirely within the view binder.
+ fun setAnimationState(state: AnimationState) {
+ _animationState.value = state
+ }
+
fun reset() {
_preview.value = null
_previewAction.value = null
_actions.value = listOf()
+ _animationState.value = AnimationState.NOT_STARTED
}
companion object {
const val TAG = "ScreenshotViewModel"
}
}
+
+enum class AnimationState {
+ NOT_STARTED,
+ ENTRANCE_STARTED, // The first 200ms of the entrance animation
+ ENTRANCE_REVEAL, // The rest of the entrance animation
+ ENTRANCE_COMPLETE,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 851bfca56359..6367d44bd439 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -47,12 +47,13 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
-import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
-import com.android.systemui.util.kotlin.BooleanFlowOperators.or
import com.android.systemui.util.kotlin.collectFlow
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -69,7 +70,6 @@ constructor(
private val communalInteractor: CommunalInteractor,
private val communalViewModel: CommunalViewModel,
private val dialogFactory: SystemUIDialogFactory,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardInteractor: KeyguardInteractor,
private val shadeInteractor: ShadeInteractor,
private val powerManager: PowerManager,
@@ -102,12 +102,9 @@ constructor(
private var rightEdgeSwipeRegionWidth: Int = 0
/**
- * True if we are currently tracking a gesture for opening the hub that started in the edge
- * swipe region.
+ * True if we are currently tracking a touch intercepted by the hub, either because the hub is
+ * open or being opened.
*/
- private var isTrackingOpenGesture = false
-
- /** True if we are currently tracking a touch on the hub while it's open. */
private var isTrackingHubTouch = false
/**
@@ -148,12 +145,12 @@ constructor(
/** Returns a flow that tracks whether communal hub is available. */
fun communalAvailable(): Flow<Boolean> =
- or(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen)
+ anyOf(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen)
/**
* Creates the container view containing the glanceable hub UI.
*
- * @throws RuntimeException if [isEnabled] is false or the view is already initialized
+ * @throws RuntimeException if the view is already initialized
*/
fun initView(
context: Context,
@@ -197,6 +194,7 @@ constructor(
/** Override for testing. */
@VisibleForTesting
internal fun initView(containerView: View): View {
+ SceneContainerFlag.assertInLegacyMode()
if (communalContainerView != null) {
throw RuntimeException("Communal view has already been initialized")
}
@@ -227,7 +225,7 @@ constructor(
// BouncerSwipeTouchHandler has a larger gesture area than we want, set an exclusion area so
// the gesture area doesn't overlap with widgets.
- // TODO(b/323035776): adjust gesture areaa for portrait mode
+ // TODO(b/323035776): adjust gesture area for portrait mode
containerView.repeatWhenAttached {
// Run when the touch handling lifecycle is RESUMED, meaning the hub is visible and not
// occluded.
@@ -250,7 +248,7 @@ constructor(
// transition to the bouncer would be incorrectly intercepted by the hub.
collectFlow(
containerView,
- or(
+ anyOf(
keyguardInteractor.primaryBouncerShowing,
keyguardInteractor.alternateBouncerShowing
),
@@ -261,7 +259,7 @@ constructor(
)
collectFlow(
containerView,
- communalInteractor.isCommunalShowing,
+ communalInteractor.isCommunalVisible,
{
hubShowing = it
updateTouchHandlingState()
@@ -269,7 +267,7 @@ constructor(
)
collectFlow(
containerView,
- and(shadeInteractor.isAnyFullyExpanded, not(shadeInteractor.isUserInteracting)),
+ allOf(shadeInteractor.isAnyFullyExpanded, not(shadeInteractor.isUserInteracting)),
{
shadeShowing = it
updateTouchHandlingState()
@@ -306,6 +304,7 @@ constructor(
/** Removes the container view from its parent. */
fun disposeView() {
+ SceneContainerFlag.assertInLegacyMode()
communalContainerView?.let {
(it.parent as ViewGroup).removeView(it)
lifecycleRegistry.currentState = Lifecycle.State.CREATED
@@ -323,71 +322,30 @@ constructor(
* to be fully in control of its own touch handling.
*/
fun onTouchEvent(ev: MotionEvent): Boolean {
+ SceneContainerFlag.assertInLegacyMode()
return communalContainerView?.let { handleTouchEventOnCommunalView(it, ev) } ?: false
}
private fun handleTouchEventOnCommunalView(view: View, ev: MotionEvent): Boolean {
- // If the hub is fully visible, send all touch events to it, other than top and bottom edge
- // swipes.
- return if (hubShowing) {
- handleHubOpenTouch(view, ev)
- } else {
- handleHubClosedTouch(view, ev)
- }
- }
-
- private fun handleHubOpenTouch(view: View, ev: MotionEvent): Boolean {
- val isDown = ev.actionMasked == MotionEvent.ACTION_DOWN
- val isUp = ev.actionMasked == MotionEvent.ACTION_UP
- val isCancel = ev.actionMasked == MotionEvent.ACTION_CANCEL
-
- val hubOccluded = anyBouncerShowing || shadeShowing
-
- if (isDown && !hubOccluded) {
- // Only intercept down events if the hub isn't occluded by the bouncer or
- // notification shade.
- isTrackingHubTouch = true
- }
-
- if (isTrackingHubTouch) {
- // Tracking a touch on the hub UI itself.
- if (isUp || isCancel) {
- isTrackingHubTouch = false
- }
- dispatchTouchEvent(view, ev)
- // Return true regardless of dispatch result as some touches at the start of a
- // gesture
- // may return false from dispatchTouchEvent.
- return true
- }
-
- return false
- }
-
- private fun handleHubClosedTouch(view: View, ev: MotionEvent): Boolean {
val isDown = ev.actionMasked == MotionEvent.ACTION_DOWN
val isUp = ev.actionMasked == MotionEvent.ACTION_UP
val isCancel = ev.actionMasked == MotionEvent.ACTION_CANCEL
val hubOccluded = anyBouncerShowing || shadeShowing
- if (rightEdgeSwipeRegionWidth == 0) {
- // If the edge region width has not been read yet for whatever reason, don't bother
- // intercepting touches to open the hub.
- return false
- }
-
if (isDown && !hubOccluded) {
val x = ev.rawX
val inOpeningSwipeRegion: Boolean = x >= view.width - rightEdgeSwipeRegionWidth
- if (inOpeningSwipeRegion) {
- isTrackingOpenGesture = true
+ if (inOpeningSwipeRegion || hubShowing) {
+ // Steal touch events when the hub is open, or if the touch started in the opening
+ // gesture region.
+ isTrackingHubTouch = true
}
}
- if (isTrackingOpenGesture) {
+ if (isTrackingHubTouch) {
if (isUp || isCancel) {
- isTrackingOpenGesture = false
+ isTrackingHubTouch = false
}
dispatchTouchEvent(view, ev)
// Return true regardless of dispatch result as some touches at the start of a gesture
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 9f1b42322151..7051d5fda159 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -620,6 +620,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
private int mDreamingToLockscreenTransitionTranslationY;
private int mLockscreenToDreamingTransitionTranslationY;
private int mGoneToDreamingTransitionTranslationY;
+ private boolean mForceFlingAnimationForTest = false;
private final SplitShadeStateController mSplitShadeStateController;
private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */);
@@ -2218,11 +2219,19 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
}
});
+ if (!mScrimController.isScreenOn() && !mForceFlingAnimationForTest) {
+ animator.setDuration(1);
+ }
setAnimator(animator);
animator.start();
}
@VisibleForTesting
+ void setForceFlingAnimationForTest(boolean force) {
+ mForceFlingAnimationForTest = force;
+ }
+
+ @VisibleForTesting
void onFlingEnd(boolean cancelled) {
mIsFlinging = false;
// No overshoot when the animation ends
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 44f86da7431e..b50a3cd442d3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -52,6 +52,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
import com.android.systemui.statusbar.DragDownHelper;
@@ -357,7 +358,9 @@ public class NotificationShadeWindowViewController implements Dumpable {
mFalsingCollector.onTouchEvent(ev);
mPulsingWakeupGestureHandler.onTouchEvent(ev);
- if (mGlanceableHubContainerController.onTouchEvent(ev)) {
+ if (!SceneContainerFlag.isEnabled()
+ && mGlanceableHubContainerController.onTouchEvent(ev)) {
+ // GlanceableHubContainerController is only used pre-flexiglass.
return logDownDispatch(ev, "dispatched to glanceable hub container", true);
}
if (mDreamingWakeupGestureHandler != null
@@ -621,6 +624,10 @@ public class NotificationShadeWindowViewController implements Dumpable {
* The layout lives in {@link R.id.communal_ui_stub}.
*/
public void setupCommunalHubLayout() {
+ if (SceneContainerFlag.isEnabled()) {
+ // GlanceableHubContainerController is only used pre-flexiglass.
+ return;
+ }
collectFlow(
mView,
mGlanceableHubContainerController.communalAvailable(),
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 5cc30bd8c27f..d2c93da671af 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -28,7 +28,6 @@ import com.android.systemui.log.LogBuffer
import com.android.systemui.log.dagger.ShadeTouchLog
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.shade.ShadeController.ShadeVisibilityListener
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -100,11 +99,9 @@ constructor(
}
override fun instantCollapseShade() {
- // TODO(b/325602936) add support for instant transition
- sceneInteractor.changeScene(
+ sceneInteractor.snapToScene(
getCollapseDestinationScene(),
"hide shade",
- CollapseShadeInstantly,
)
}
@@ -203,7 +200,11 @@ constructor(
}
override fun expandToQs() {
- sceneInteractor.changeScene(Scenes.QuickSettings, "ShadeController.animateExpandQs")
+ val shadeMode = shadeInteractor.shadeMode.value
+ sceneInteractor.changeScene(
+ if (shadeMode is ShadeMode.Dual) Scenes.QuickSettingsShade else Scenes.QuickSettings,
+ "ShadeController.animateExpandQs"
+ )
}
override fun setVisibilityListener(listener: ShadeVisibilityListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/slice/SliceViewManagerExt.kt b/packages/SystemUI/src/com/android/systemui/slice/SliceViewManagerExt.kt
index 384acc493c4a..dd7942503211 100644
--- a/packages/SystemUI/src/com/android/systemui/slice/SliceViewManagerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/slice/SliceViewManagerExt.kt
@@ -28,6 +28,9 @@ import kotlinx.coroutines.launch
* Returns updating [Slice] for a [sliceUri]. It's null when there is no slice available for the
* provided Uri. This can change overtime because of external changes (like device being
* connected/disconnected).
+ *
+ * The flow should be [kotlinx.coroutines.flow.flowOn] the main thread because [SliceViewManager]
+ * isn't thread-safe. An exception will be thrown otherwise.
*/
fun SliceViewManager.sliceForUri(sliceUri: Uri): Flow<Slice?> =
ConflatedCallbackFlow.conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 222b070d151d..14e14f4bd47f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -14,7 +14,6 @@ import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.ExpandHelper
-import com.android.systemui.Flags.nsslFalsingFix
import com.android.systemui.Gefingerpoken
import com.android.systemui.biometrics.UdfpsKeyguardViewControllerLegacy
import com.android.systemui.classifier.Classifier
@@ -884,9 +883,7 @@ class DragDownHelper(
isDraggingDown = false
isTrackpadReverseScroll = false
shadeRepository.setLegacyLockscreenShadeTracking(false)
- if (nsslFalsingFix() || MigrateClocksToBlueprint.isEnabled) {
- return true
- }
+ return true
} else {
stopDragging()
return false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 96a50f7686b9..70632d5aa27a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -679,6 +679,7 @@ public class StatusBarStateControllerImpl implements
Scenes.Shade, StatusBarState.SHADE_LOCKED,
Scenes.NotificationsShade, StatusBarState.SHADE_LOCKED,
Scenes.QuickSettings, StatusBarState.SHADE_LOCKED,
+ Scenes.QuickSettingsShade, StatusBarState.SHADE_LOCKED,
Scenes.Gone, StatusBarState.SHADE
);
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 61cdea190a43..6a38f8df4715 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
@@ -38,6 +38,7 @@ import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.res.R;
+import com.android.systemui.shade.TouchLogger;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -745,6 +746,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ return TouchLogger.logDispatchTouch(
+ getClass().getSimpleName(), ev, super.dispatchTouchEvent(ev));
+ }
+
/**
* SourceType which should be reset when this View is detached
* @param sourceType will be reset on View detached
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt
index 9a54de1481a0..2527af87728e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row.ui.viewbinder
+import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
@@ -72,7 +73,6 @@ private class TouchHandler(
var isTouchEnabled = false
override fun onTouch(v: View, ev: MotionEvent): Boolean {
- val result = false
if (ev.action == MotionEvent.ACTION_UP) {
view.setLastActionUpTime(ev.eventTime)
}
@@ -82,13 +82,22 @@ private class TouchHandler(
}
if (ev.action == MotionEvent.ACTION_UP) {
// If this is a false tap, capture the even so it doesn't result in a click.
- return falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)
+ return falsingManager.isFalseTap(FalsingManager.LOW_PENALTY).also {
+ if (it) {
+ Log.d(v::class.simpleName ?: TAG, "capturing false tap")
+ }
+ }
}
- return result
+ return false
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean = false
/** Use [onTouch] instead. */
override fun onTouchEvent(ev: MotionEvent): Boolean = false
+
+ companion object {
+ private const val TAG = "ActivatableNotificationViewBinder"
+ }
}
+
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 3bd873580fbb..773a6bf752a6 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
@@ -126,7 +126,6 @@ import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.util.Assert;
import com.android.systemui.util.ColorUtilKt;
-import com.android.systemui.util.Compile;
import com.android.systemui.util.DumpUtilsKt;
import com.google.errorprone.annotations.CompileTimeConstant;
@@ -156,7 +155,6 @@ public class NotificationStackScrollLayout
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
private static final boolean SPEW = Log.isLoggable(TAG, Log.VERBOSE);
- private static final boolean DEBUG_UPDATE_SIDE_PADDING = Compile.IS_DEBUG;
private boolean mShadeNeedsToClose = false;
@@ -933,11 +931,6 @@ public class NotificationStackScrollLayout
+ " mSkinnyNotifsInLandscape=" + mSkinnyNotifsInLandscape;
mLastInitViewElapsedRealtime = SystemClock.elapsedRealtime();
- if (DEBUG_UPDATE_SIDE_PADDING) {
- Log.v(TAG, "initView @ elapsedRealtime " + mLastInitViewElapsedRealtime + ": "
- + mLastInitViewDumpString);
- }
-
mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height);
mStackScrollAlgorithm.initView(context);
mStateAnimator.initView(context);
@@ -967,12 +960,6 @@ public class NotificationStackScrollLayout
+ " orientation=" + orientation;
mLastUpdateSidePaddingElapsedRealtime = SystemClock.elapsedRealtime();
- if (DEBUG_UPDATE_SIDE_PADDING) {
- Log.v(TAG,
- "updateSidePadding @ elapsedRealtime " + mLastUpdateSidePaddingElapsedRealtime
- + ": " + mLastUpdateSidePaddingDumpString);
- }
-
if (viewWidth == 0) {
Log.e(TAG, "updateSidePadding: viewWidth is zero");
mSidePaddings = mMinimumPaddings;
@@ -1185,6 +1172,11 @@ public class NotificationStackScrollLayout
}
@Override
+ public void setCurrentGestureOverscrollConsumer(@Nullable Consumer<Boolean> consumer) {
+ mScrollViewFields.setCurrentGestureOverscrollConsumer(consumer);
+ }
+
+ @Override
public void setStackHeightConsumer(@Nullable Consumer<Float> consumer) {
mScrollViewFields.setStackHeightConsumer(consumer);
}
@@ -3403,6 +3395,8 @@ public class NotificationStackScrollLayout
boolean isUpOrCancel = action == ACTION_UP || action == ACTION_CANCEL;
if (mSendingTouchesToSceneFramework) {
mController.sendTouchToSceneFramework(ev);
+ mScrollViewFields.sendCurrentGestureOverscroll(
+ getExpandedInThisMotion() && !isUpOrCancel);
} else if (!isUpOrCancel) {
// if this is the first touch being sent to the scene framework,
// convert it into a synthetic DOWN event.
@@ -3410,6 +3404,7 @@ public class NotificationStackScrollLayout
MotionEvent downEvent = MotionEvent.obtain(ev);
downEvent.setAction(MotionEvent.ACTION_DOWN);
mController.sendTouchToSceneFramework(downEvent);
+ mScrollViewFields.sendCurrentGestureOverscroll(getExpandedInThisMotion());
downEvent.recycle();
}
@@ -3428,6 +3423,14 @@ public class NotificationStackScrollLayout
downEvent.recycle();
}
+ // Only when scene container is enabled, mark that we are being dragged so that we start
+ // dispatching the rest of the gesture to scene container.
+ void startOverscrollAfterExpanding() {
+ SceneContainerFlag.isUnexpectedlyInLegacyMode();
+ getExpandHelper().finishExpanding();
+ setIsBeingDragged(true);
+ }
+
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (!isScrollingEnabled()
@@ -5545,6 +5548,11 @@ public class NotificationStackScrollLayout
return mExpandingNotification;
}
+ @VisibleForTesting
+ void setExpandingNotification(boolean isExpanding) {
+ mExpandingNotification = isExpanding;
+ }
+
boolean getDisallowScrollingInThisMotion() {
return mDisallowScrollingInThisMotion;
}
@@ -5557,6 +5565,11 @@ public class NotificationStackScrollLayout
return mExpandedInThisMotion;
}
+ @VisibleForTesting
+ void setExpandedInThisMotion(boolean expandedInThisMotion) {
+ mExpandedInThisMotion = expandedInThisMotion;
+ }
+
boolean getDisallowDismissInThisMotion() {
return mDisallowDismissInThisMotion;
}
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 5bb3f4273c52..c1c63cdec448 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
@@ -23,7 +23,6 @@ import static com.android.app.animation.Interpolators.STANDARD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
import static com.android.server.notification.Flags.screenshareNotificationHiding;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
-import static com.android.systemui.Flags.nsslFalsingFix;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnOverscrollTopChangedListener;
@@ -206,6 +205,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
private final SeenNotificationsInteractor mSeenNotificationsInteractor;
private final KeyguardTransitionRepository mKeyguardTransitionRepo;
private NotificationStackScrollLayout mView;
+ private TouchHandler mTouchHandler;
private NotificationSwipeHelper mSwipeHelper;
@Nullable
private Boolean mHistoryEnabled;
@@ -807,7 +807,8 @@ public class NotificationStackScrollLayoutController implements Dumpable {
mView.setStackStateLogger(mStackStateLogger);
mView.setController(this);
mView.setLogger(mLogger);
- mView.setTouchHandler(new TouchHandler());
+ mTouchHandler = new TouchHandler();
+ mView.setTouchHandler(mTouchHandler);
mView.setResetUserExpandedStatesRunnable(mNotificationsController::resetUserExpandedStates);
mView.setActivityStarter(mActivityStarter);
mView.setClearAllAnimationListener(this::onAnimationEnd);
@@ -1793,6 +1794,11 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
}
+ @VisibleForTesting
+ TouchHandler getTouchHandler() {
+ return mTouchHandler;
+ }
+
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mMaxAlphaFromView=" + mMaxAlphaFromView);
@@ -2043,37 +2049,30 @@ public class NotificationStackScrollLayoutController implements Dumpable {
expandingNotification = mView.isExpandingNotification();
if (mView.getExpandedInThisMotion() && !expandingNotification && wasExpandingBefore
&& !mView.getDisallowScrollingInThisMotion()) {
- mView.dispatchDownEventToScroller(ev);
+ // We need to dispatch the overscroll differently when Scene Container is on,
+ // since NSSL no longer controls its own scroll.
+ if (SceneContainerFlag.isEnabled() && !isCancelOrUp) {
+ mView.startOverscrollAfterExpanding();
+ return true;
+ } else {
+ mView.dispatchDownEventToScroller(ev);
+ }
}
}
boolean horizontalSwipeWantsIt = false;
boolean scrollerWantsIt = false;
- if (nsslFalsingFix() || MigrateClocksToBlueprint.isEnabled()) {
- // Reverse the order relative to the else statement. onScrollTouch will reset on an
- // UP event, causing horizontalSwipeWantsIt to be set to true on vertical swipes.
- if (mLongPressedView == null && !mView.isBeingDragged()
- && !expandingNotification
- && !mView.getExpandedInThisMotion()
- && !onlyScrollingInThisMotion
- && !mView.getDisallowDismissInThisMotion()) {
- horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
- }
- if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
- && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
- scrollerWantsIt = mView.onScrollTouch(ev);
- }
- } else {
- if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
- && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
- scrollerWantsIt = mView.onScrollTouch(ev);
- }
- if (mLongPressedView == null && !mView.isBeingDragged()
- && !expandingNotification
- && !mView.getExpandedInThisMotion()
- && !onlyScrollingInThisMotion
- && !mView.getDisallowDismissInThisMotion()) {
- horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
- }
+ // NOTE: the order of these is important. If reversed, onScrollTouch will reset on an
+ // UP event, causing horizontalSwipeWantsIt to be set to true on vertical swipes.
+ if (mLongPressedView == null && !mView.isBeingDragged()
+ && !expandingNotification
+ && !mView.getExpandedInThisMotion()
+ && !onlyScrollingInThisMotion
+ && !mView.getDisallowDismissInThisMotion()) {
+ horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ }
+ if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
+ && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
+ scrollerWantsIt = mView.onScrollTouch(ev);
}
// Check if we need to clear any snooze leavebehinds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
index edac5ede1e91..a3827c140214 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
@@ -51,6 +51,11 @@ class ScrollViewFields {
*/
var syntheticScrollConsumer: Consumer<Float>? = null
/**
+ * When a gesture is consumed internally by NSSL but needs to be handled by other elements (such
+ * as the notif scrim) as overscroll, we can notify the placeholder through here.
+ */
+ var currentGestureOverscrollConsumer: Consumer<Boolean>? = null
+ /**
* Any time the stack height is recalculated, it should be updated here to be used by the
* placeholder
*/
@@ -64,6 +69,9 @@ class ScrollViewFields {
/** send the [syntheticScroll] to the [syntheticScrollConsumer], if present. */
fun sendSyntheticScroll(syntheticScroll: Float) =
syntheticScrollConsumer?.accept(syntheticScroll)
+ /** send [isCurrentGestureOverscroll] to the [currentGestureOverscrollConsumer], if present. */
+ fun sendCurrentGestureOverscroll(isCurrentGestureOverscroll: Boolean) =
+ currentGestureOverscrollConsumer?.accept(isCurrentGestureOverscroll)
/** send the [stackHeight] to the [stackHeightConsumer], if present. */
fun sendStackHeight(stackHeight: Float) = stackHeightConsumer?.accept(stackHeight)
/** send the [headsUpHeight] to the [headsUpHeightConsumer], if present. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index e980794d23dd..d0cebae40c5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -169,6 +169,14 @@ public class StackScrollAlgorithm {
}
}
+ // On the final call to {@link #resetViewState}, the alpha is set back to 1f but
+ // ambientState.isExpansionChanging() is now false. This causes a flicker on the
+ // EmptyShadeView after the shade is collapsed. Make sure the empty shade view
+ // isn't visible unless the shade is expanded.
+ if (view instanceof EmptyShadeView && ambientState.getExpansionFraction() == 0f) {
+ viewState.setAlpha(0f);
+ }
+
// For EmptyShadeView if on keyguard, we need to control the alpha to create
// a nice transition when the user is dragging down the notification panel.
if (view instanceof EmptyShadeView && ambientState.isOnKeyguard()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt
index 8a9da69079d4..920c9c213060 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt
@@ -43,4 +43,10 @@ class NotificationViewHeightRepository @Inject constructor() {
* necessary to scroll up to keep expanding the notification.
*/
val syntheticScroll = MutableStateFlow(0f)
+
+ /**
+ * Whether the current touch gesture is overscroll. If true, it means the NSSL has already
+ * consumed part of the gesture.
+ */
+ val isCurrentGestureOverscroll = MutableStateFlow(false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
index b8660bad78d9..b94da388cef4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
@@ -105,6 +105,13 @@ constructor(
*/
val syntheticScroll: Flow<Float> = viewHeightRepository.syntheticScroll.asStateFlow()
+ /**
+ * Whether the current touch gesture is overscroll. If true, it means the NSSL has already
+ * consumed part of the gesture.
+ */
+ val isCurrentGestureOverscroll: Flow<Boolean> =
+ viewHeightRepository.isCurrentGestureOverscroll.asStateFlow()
+
/** Sets the alpha to apply to the NSSL for the brightness mirror */
fun setAlphaForBrightnessMirror(alpha: Float) {
placeholderRepository.alphaForBrightnessMirror.value = alpha
@@ -146,6 +153,11 @@ constructor(
viewHeightRepository.syntheticScroll.value = delta
}
+ /** Sets whether the current touch gesture is overscroll. */
+ fun setCurrentGestureOverscroll(isOverscroll: Boolean) {
+ viewHeightRepository.isCurrentGestureOverscroll.value = isOverscroll
+ }
+
fun setConstrainedAvailableSpace(height: Int) {
placeholderRepository.constrainedAvailableSpace.value = height
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
index 20e8cac6e94b..9b21fa9bbe35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
@@ -29,11 +29,10 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
@@ -54,9 +53,9 @@ constructor(
private val _topPosition = MutableStateFlow(0f)
val topPosition = _topPosition.asStateFlow()
- private val _notificationStackChanged = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
+ private val _notificationStackChanged = MutableStateFlow(0L)
/** An internal modification was made to notifications */
- val notificationStackChanged = _notificationStackChanged.asSharedFlow()
+ val notificationStackChanged = _notificationStackChanged.debounce(20L)
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
configurationRepository.onAnyConfigurationChange
@@ -113,7 +112,7 @@ constructor(
/** An internal modification was made to notifications */
fun notificationStackChanged() {
- _notificationStackChanged.tryEmit(Unit)
+ _notificationStackChanged.value = _notificationStackChanged.value + 1
}
data class ConfigurationBasedDimensions(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
index a56384dc47dd..2c8884504c32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
@@ -51,6 +51,8 @@ interface NotificationScrollView {
/** Set a consumer for synthetic scroll events */
fun setSyntheticScrollConsumer(consumer: Consumer<Float>?)
+ /** Set a consumer for current gesture overscroll events */
+ fun setCurrentGestureOverscrollConsumer(consumer: Consumer<Boolean>?)
/** Set a consumer for stack height changed events */
fun setStackHeightConsumer(consumer: Consumer<Float>?)
/** Set a consumer for heads up height changed events */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index 4476d87fbcf6..26f7ad775f1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -89,10 +89,12 @@ constructor(
launchAndDispose {
view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer)
+ view.setCurrentGestureOverscrollConsumer(viewModel.currentGestureOverscrollConsumer)
view.setStackHeightConsumer(viewModel.stackHeightConsumer)
view.setHeadsUpHeightConsumer(viewModel.headsUpHeightConsumer)
DisposableHandle {
view.setSyntheticScrollConsumer(null)
+ view.setCurrentGestureOverscrollConsumer(null)
view.setStackHeightConsumer(null)
view.setHeadsUpHeightConsumer(null)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 8b1b93bfb0e5..b2184db0879d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -145,6 +145,12 @@ constructor(
/** Receives the amount (px) that the stack should scroll due to internal expansion. */
val syntheticScrollConsumer: (Float) -> Unit = stackAppearanceInteractor::setSyntheticScroll
+ /**
+ * Receives whether the current touch gesture is overscroll as it has already been consumed by
+ * the stack.
+ */
+ val currentGestureOverscrollConsumer: (Boolean) -> Unit =
+ stackAppearanceInteractor::setCurrentGestureOverscroll
/** Receives the height of the contents of the notification stack. */
val stackHeightConsumer: (Float) -> Unit = stackAppearanceInteractor::setStackHeight
/** Receives the height of the heads up notification. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
index 486e305af05f..11eaf54efe47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -111,6 +111,13 @@ constructor(
val syntheticScroll: Flow<Float> =
interactor.syntheticScroll.dumpWhileCollecting("syntheticScroll")
+ /**
+ * Whether the current touch gesture is overscroll. If true, it means the NSSL has already
+ * consumed part of the gesture.
+ */
+ val isCurrentGestureOverscroll: Flow<Boolean> =
+ interactor.isCurrentGestureOverscroll.dumpWhileCollecting("isCurrentGestureOverScroll")
+
/** Sets whether the notification stack is scrolled to the top. */
fun setScrolledToTop(scrolledToTop: Boolean) {
interactor.setScrolledToTop(scrolledToTop)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index ac4bd09b1687..0ba7b3c214c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -68,8 +68,8 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
-import com.android.systemui.util.kotlin.BooleanFlowOperators.and
-import com.android.systemui.util.kotlin.BooleanFlowOperators.or
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.FlowDumperImpl
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import javax.inject.Inject
@@ -246,7 +246,7 @@ constructor(
keyguardTransitionInteractor.finishedKeyguardState.map { state ->
state == GLANCEABLE_HUB
},
- or(
+ anyOf(
keyguardTransitionInteractor.isInTransitionToState(GLANCEABLE_HUB),
keyguardTransitionInteractor.isInTransitionFromState(GLANCEABLE_HUB),
),
@@ -424,14 +424,14 @@ constructor(
while (currentCoroutineContext().isActive) {
emit(false)
// Ensure states are inactive to start
- and(
+ allOf(
*toFlowArray(statesForHiddenKeyguard) { state ->
keyguardTransitionInteractor.transitionValue(state).map { it == 0f }
}
)
.first { it }
// Wait for a qualifying transition to begin
- or(
+ anyOf(
*toFlowArray(statesForHiddenKeyguard) { state ->
keyguardTransitionInteractor
.transitionStepsToState(state)
@@ -446,7 +446,7 @@ constructor(
// it is considered safe to reset alpha to 1f for HUNs.
combine(
keyguardInteractor.statusBarState,
- and(
+ allOf(
*toFlowArray(statesForHiddenKeyguard) { state ->
keyguardTransitionInteractor.transitionValue(state).map {
it == 0f
@@ -636,7 +636,7 @@ constructor(
showUnlimitedNotifications,
shadeInteractor.isUserInteracting,
availableHeight,
- interactor.notificationStackChanged.onStart { emit(Unit) },
+ interactor.notificationStackChanged,
interactor.useExtraShelfSpace,
) { flows ->
val showLimitedNotifications = flows[0] as Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index dea94162ad0e..2e1ab383538f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -59,7 +59,10 @@ class ConfigurationControllerImpl @Inject constructor(
}
override fun notifyThemeChanged() {
- val listeners = ArrayList(listeners)
+ // Avoid concurrent modification exception
+ val listeners = synchronized(this.listeners) {
+ ArrayList(this.listeners)
+ }
listeners.filterForEach({ this.listeners.contains(it) }) {
it.onThemeChanged()
@@ -68,8 +71,9 @@ class ConfigurationControllerImpl @Inject constructor(
override fun onConfigurationChanged(newConfig: Configuration) {
// Avoid concurrent modification exception
- val listeners = ArrayList(listeners)
-
+ val listeners = synchronized(this.listeners) {
+ ArrayList(this.listeners)
+ }
listeners.filterForEach({ this.listeners.contains(it) }) {
it.onConfigChanged(newConfig)
}
@@ -148,12 +152,16 @@ class ConfigurationControllerImpl @Inject constructor(
}
override fun addCallback(listener: ConfigurationListener) {
- listeners.add(listener)
+ synchronized(listeners) {
+ listeners.add(listener)
+ }
listener.onDensityOrFontScaleChanged()
}
override fun removeCallback(listener: ConfigurationListener) {
- listeners.remove(listener)
+ synchronized(listeners) {
+ listeners.remove(listener)
+ }
}
override fun isLayoutRtl(): Boolean {
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 0a88d6358d8e..74182fc4d2c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1644,6 +1644,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mScreenOn = false;
}
+ public boolean isScreenOn() {
+ return mScreenOn;
+ }
+
public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
mExpansionAffectsAlpha = expansionAffectsAlpha;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 226a84a78116..88ca9e5f1744 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -229,7 +229,7 @@ abstract class StatusBarPipelineModule {
@SysUISingleton
@OemSatelliteInputLog
fun provideOemSatelliteInputLog(factory: LogBufferFactory): LogBuffer {
- return factory.create("DeviceBasedSatelliteInputLog", 32)
+ return factory.create("DeviceBasedSatelliteInputLog", 150)
}
const val FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index 0739b8362420..12f252d215a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -249,11 +249,17 @@ constructor(
try {
sm.registerForNtnSignalStrengthChanged(bgDispatcher.asExecutor(), cb)
registered = true
+ logBuffer.i { "Registered for signal strength successfully" }
} catch (e: Exception) {
logBuffer.e("error registering for signal strength", e)
}
- awaitClose { if (registered) sm.unregisterForNtnSignalStrengthChanged(cb) }
+ awaitClose {
+ if (registered) {
+ sm.unregisterForNtnSignalStrengthChanged(cb)
+ logBuffer.i { "Unregistered for signal strength successfully" }
+ }
+ }
}
.flowOn(bgDispatcher)
@@ -318,8 +324,8 @@ constructor(
}
companion object {
- // TTL for satellite polling is one hour
- const val POLLING_INTERVAL_MS: Long = 1000 * 60 * 60
+ // TTL for satellite polling is twenty minutes
+ const val POLLING_INTERVAL_MS: Long = 1000 * 60 * 20
// Let the system boot up and stabilize before we check for system support
const val MIN_UPTIME: Long = 1000 * 60
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index 37be1c6aa73d..a817b31070a1 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -18,6 +18,7 @@
package com.android.systemui.user.data.repository
import android.annotation.SuppressLint
+import android.annotation.UserIdInt
import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
@@ -107,6 +108,22 @@ interface UserRepository {
fun isSimpleUserSwitcher(): Boolean
fun isUserSwitcherEnabled(): Boolean
+
+ /**
+ * Returns the user ID of the "main user" of the device. This user may have access to certain
+ * features which are limited to at most one user. There will never be more than one main user
+ * on a device.
+ *
+ * <p>Currently, on most form factors the first human user on the device will be the main user;
+ * in the future, the concept may be transferable, so a different user (or even no user at all)
+ * may be designated the main user instead. On other form factors there might not be a main
+ * user.
+ *
+ * <p> When the device doesn't have a main user, this will return {@code null}.
+ *
+ * @see [UserManager.getMainUser]
+ */
+ @UserIdInt suspend fun getMainUserId(): Int?
}
@SysUISingleton
@@ -239,6 +256,10 @@ constructor(
return _userSwitcherSettings.value.isUserSwitcherEnabled
}
+ override suspend fun getMainUserId(): Int? {
+ return withContext(backgroundDispatcher) { manager.mainUser?.identifier }
+ }
+
private suspend fun getSettings(): UserSwitcherSettingsModel {
return withContext(backgroundDispatcher) {
val isSimpleUserSwitcher =
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
index 38b381ac543e..59c819d41493 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
@@ -2,6 +2,7 @@ package com.android.systemui.user.domain.interactor
import android.annotation.UserIdInt
import android.content.pm.UserInfo
+import android.os.UserManager
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.Flags.refactorGetCurrentUser
import com.android.systemui.dagger.SysUISingleton
@@ -38,4 +39,23 @@ class SelectedUserInteractor @Inject constructor(private val repository: UserRep
KeyguardUpdateMonitor.getCurrentUser()
}
}
+
+ /**
+ * Returns the user ID of the "main user" of the device. This user may have access to certain
+ * features which are limited to at most one user. There will never be more than one main user
+ * on a device.
+ *
+ * <p>Currently, on most form factors the first human user on the device will be the main user;
+ * in the future, the concept may be transferable, so a different user (or even no user at all)
+ * may be designated the main user instead. On other form factors there might not be a main
+ * user.
+ *
+ * <p> When the device doesn't have a main user, this will return {@code null}.
+ *
+ * @see [UserManager.getMainUser]
+ */
+ @UserIdInt
+ fun getMainUserId(): Int? {
+ return repository.mainUserId
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt
index b3008856d370..a2759c6bf470 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt
@@ -28,11 +28,23 @@ object BooleanFlowOperators {
*
* Usage:
* ```
- * val result = and(flow1, flow2)
+ * val result = allOf(flow1, flow2)
* ```
*/
- fun and(vararg flows: Flow<Boolean>): Flow<Boolean> =
- combine(flows.asIterable()) { values -> values.all { it } }.distinctUntilChanged()
+ fun allOf(vararg flows: Flow<Boolean>): Flow<Boolean> = flows.asIterable().all()
+
+ /**
+ * Logical AND operator for boolean flows. Will collect all flows and [combine] them to
+ * determine the result.
+ */
+ fun Array<Flow<Boolean>>.all(): Flow<Boolean> = allOf(*this)
+
+ /**
+ * Logical AND operator for boolean flows. Will collect all flows and [combine] them to
+ * determine the result.
+ */
+ fun Iterable<Flow<Boolean>>.all(): Flow<Boolean> =
+ combine(this) { values -> values.all { it } }.distinctUntilChanged()
/**
* Logical NOT operator for a boolean flow.
@@ -48,6 +60,36 @@ object BooleanFlowOperators {
* Logical OR operator for a boolean flow. Will collect all flows and [combine] them to
* determine the result.
*/
- fun or(vararg flows: Flow<Boolean>): Flow<Boolean> =
- combine(flows.asIterable()) { values -> values.any { it } }.distinctUntilChanged()
+ fun anyOf(vararg flows: Flow<Boolean>): Flow<Boolean> = flows.asIterable().any()
+
+ /**
+ * Logical OR operator for a boolean flow. Will collect all flows and [combine] them to
+ * determine the result.
+ */
+ fun Array<Flow<Boolean>>.any(): Flow<Boolean> = anyOf(*this)
+
+ /**
+ * Logical OR operator for a boolean flow. Will collect all flows and [combine] them to
+ * determine the result.
+ */
+ fun Iterable<Flow<Boolean>>.any(): Flow<Boolean> =
+ combine(this) { values -> values.any { it } }.distinctUntilChanged()
+
+ /**
+ * Returns a Flow that produces `true` when all input flows are producing `false`, otherwise
+ * produces `false`.
+ */
+ fun noneOf(vararg flows: Flow<Boolean>): Flow<Boolean> = not(anyOf(*flows))
+
+ /**
+ * Returns a Flow that produces `true` when all input flows are producing `false`, otherwise
+ * produces `false`.
+ */
+ fun Array<Flow<Boolean>>.none(): Flow<Boolean> = noneOf(*this)
+
+ /**
+ * Returns a Flow that produces `true` when all input flows are producing `false`, otherwise
+ * produces `false`.
+ */
+ fun Iterable<Flow<Boolean>>.none(): Flow<Boolean> = not(any())
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
index 8ce3b1fa1e73..3117abc44111 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
@@ -23,6 +23,7 @@ import androidx.slice.SliceViewManager
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.media.BluetoothMediaDevice
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.slice.sliceForUri
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import dagger.assisted.Assisted
@@ -57,6 +58,7 @@ class AncSliceRepositoryImpl
constructor(
mediaRepositoryFactory: LocalMediaRepositoryFactory,
@Background private val backgroundCoroutineContext: CoroutineContext,
+ @Main private val mainCoroutineContext: CoroutineContext,
@Assisted private val sliceViewManager: SliceViewManager,
) : AncSliceRepository {
@@ -73,7 +75,7 @@ constructor(
.distinctUntilChanged()
.flatMapLatest { sliceUri ->
sliceUri ?: return@flatMapLatest flowOf(null)
- sliceViewManager.sliceForUri(sliceUri)
+ sliceViewManager.sliceForUri(sliceUri).flowOn(mainCoroutineContext)
}
.flowOn(backgroundCoroutineContext)
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt
index bee79bb68141..c980eb43ec97 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt
@@ -16,7 +16,9 @@
package com.android.systemui.volume.panel.component.anc.ui.viewmodel
+import android.content.Intent
import androidx.slice.Slice
+import androidx.slice.SliceItem
import com.android.systemui.volume.panel.component.anc.domain.AncAvailabilityCriteria
import com.android.systemui.volume.panel.component.anc.domain.interactor.AncSliceInteractor
import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
@@ -59,6 +61,31 @@ constructor(
.map { it.buttonSlice }
.stateIn(coroutineScope, SharingStarted.Eagerly, null)
+ fun isClickable(slice: Slice?): Boolean {
+ slice ?: return false
+ val slices = ArrayDeque<SliceItem>()
+ slices.addAll(slice.items)
+ while (slices.isNotEmpty()) {
+ val item: SliceItem = slices.removeFirst()
+ when (item.format) {
+ android.app.slice.SliceItem.FORMAT_ACTION -> {
+ val itemActionIntent: Intent? = item.action?.intent
+ if (itemActionIntent?.hasExtra(EXTRA_ANC_ENABLED) == true) {
+ return itemActionIntent.getBooleanExtra(EXTRA_ANC_ENABLED, true)
+ }
+ }
+ android.app.slice.SliceItem.FORMAT_SLICE -> {
+ item.slice?.items?.let(slices::addAll)
+ }
+ }
+ }
+ return true
+ }
+
+ private companion object {
+ const val EXTRA_ANC_ENABLED = "EXTRA_ANC_ENABLED"
+ }
+
/** Call this to update [popupSlice] width in a reaction to container size change. */
fun onPopupSliceWidthChanged(width: Int) {
interactor.onPopupSliceWidthChanged(width)
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 263ddc175647..b86a7c92ba47 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -21,6 +21,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_B
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
@@ -273,6 +274,13 @@ public final class WMShell implements
splitScreen.setSplitscreenFocus(leftOrTop);
}
});
+ splitScreen.registerSplitAnimationListener(new SplitScreen.SplitInvocationListener() {
+ @Override
+ public void onSplitAnimationInvoked(boolean animationRunning) {
+ mSysUiState.setFlag(SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION, animationRunning)
+ .commitUpdate(mDisplayTracker.getDefaultDisplayId());
+ }
+ }, mSysUiMainExecutor);
}
@VisibleForTesting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 67ca9a40dc2a..023148603b50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -16,80 +16,73 @@
package com.android.systemui.biometrics
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
-import dagger.BindsInstance
-import dagger.Component
+import com.android.systemui.flags.andSceneContainer
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.shadeTestUtil
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.verifyZeroInteractions
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
-
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- BiometricsDomainLayerModule::class,
- ]
- )
- interface TestComponent : SysUITestComponent<AuthDialogPanelInteractionDetector> {
-
- val shadeRepository: FakeShadeRepository
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- ): TestComponent
+@RunWith(ParameterizedAndroidJunit4::class)
+class AuthDialogPanelInteractionDetectorTest(flags: FlagsParameterization?) : SysuiTestCase() {
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
}
}
- private val testComponent: TestComponent =
- DaggerAuthDialogPanelInteractionDetectorTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
- )
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
- private val detector: AuthDialogPanelInteractionDetector = testComponent.underTest
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
@Mock private lateinit var action: Runnable
+ lateinit var detector: AuthDialogPanelInteractionDetector
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ detector =
+ AuthDialogPanelInteractionDetector(
+ kosmos.applicationCoroutineScope,
+ { kosmos.shadeInteractor },
+ )
}
@Test
fun enableDetector_expand_shouldRunAction() =
- testComponent.runTest {
+ testScope.runTest {
// GIVEN shade is closed and detector is enabled
- shadeRepository.setLegacyShadeExpansion(0f)
+ shadeTestUtil.setShadeExpansion(0f)
detector.enable(action)
runCurrent()
// WHEN shade expands
- shadeRepository.setLegacyShadeTracking(true)
- shadeRepository.setLegacyShadeExpansion(.5f)
+ shadeTestUtil.setTracking(true)
+ shadeTestUtil.setShadeExpansion(.5f)
runCurrent()
// THEN action was run
@@ -98,9 +91,9 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
@Test
fun enableDetector_isUserInteractingTrue_shouldNotPostRunnable() =
- testComponent.runTest {
+ testScope.runTest {
// GIVEN isInteracting starts true
- shadeRepository.setLegacyShadeTracking(true)
+ shadeTestUtil.setTracking(true)
runCurrent()
detector.enable(action)
@@ -110,33 +103,34 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
@Test
fun enableDetector_shadeExpandImmediate_shouldNotPostRunnable() =
- testComponent.runTest {
+ testScope.runTest {
// GIVEN shade is closed and detector is enabled
- shadeRepository.setLegacyShadeExpansion(0f)
+ shadeTestUtil.setShadeExpansion(0f)
detector.enable(action)
runCurrent()
// WHEN shade expands fully instantly
- shadeRepository.setLegacyShadeExpansion(1f)
+ shadeTestUtil.setShadeExpansion(1f)
runCurrent()
// THEN action not run
verifyZeroInteractions(action)
+ detector.disable()
}
@Test
fun disableDetector_shouldNotPostRunnable() =
- testComponent.runTest {
+ testScope.runTest {
// GIVEN shade is closed and detector is enabled
- shadeRepository.setLegacyShadeExpansion(0f)
+ shadeTestUtil.setShadeExpansion(0f)
detector.enable(action)
runCurrent()
// WHEN detector is disabled and shade opens
detector.disable()
runCurrent()
- shadeRepository.setLegacyShadeTracking(true)
- shadeRepository.setLegacyShadeExpansion(.5f)
+ shadeTestUtil.setTracking(true)
+ shadeTestUtil.setShadeExpansion(.5f)
runCurrent()
// THEN action not run
@@ -145,17 +139,18 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
@Test
fun enableDetector_beginCollapse_shouldNotPostRunnable() =
- testComponent.runTest {
+ testScope.runTest {
// GIVEN shade is open and detector is enabled
- shadeRepository.setLegacyShadeExpansion(1f)
+ shadeTestUtil.setShadeExpansion(1f)
detector.enable(action)
runCurrent()
// WHEN shade begins to collapse
- shadeRepository.setLegacyShadeExpansion(.5f)
+ shadeTestUtil.programmaticCollapseShade()
runCurrent()
// THEN action not run
verifyZeroInteractions(action)
+ detector.disable()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
index af1d31528675..f62a55d02f61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
@@ -77,6 +77,8 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
@Mock private lateinit var deviceItemInteractor: DeviceItemInteractor
+ @Mock private lateinit var deviceItemActionInteractor: DeviceItemActionInteractor
+
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator
@@ -118,6 +120,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
bluetoothTileDialogViewModel =
BluetoothTileDialogViewModel(
deviceItemInteractor,
+ deviceItemActionInteractor,
BluetoothStateInteractor(
localBluetoothManager,
bluetoothTileDialogLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt
new file mode 100644
index 000000000000..762137bede27
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bluetooth.qsdialog
+
+import android.bluetooth.BluetoothDevice
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.whenever
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
+class DeviceItemActionInteractorImplTest : SysuiTestCase() {
+ @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
+ private lateinit var actionInteractorImpl: DeviceItemActionInteractor
+
+ @Mock private lateinit var dialog: SystemUIDialog
+ @Mock private lateinit var cachedDevice: CachedBluetoothDevice
+ @Mock private lateinit var device: BluetoothDevice
+ @Mock private lateinit var deviceItem: DeviceItem
+
+ @Before
+ fun setUp() {
+ actionInteractorImpl = kosmos.deviceItemActionInteractor
+ whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedDevice)
+ whenever(cachedDevice.address).thenReturn("ADDRESS")
+ whenever(cachedDevice.device).thenReturn(device)
+ }
+
+ @Test
+ fun testOnClick_connectedMedia_setActive() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(deviceItem.type)
+ .thenReturn(DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
+ actionInteractorImpl.onClick(deviceItem, dialog)
+ verify(cachedDevice).setActive()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedDevice.address,
+ DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_activeMedia_disconnect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(deviceItem.type).thenReturn(DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
+ actionInteractorImpl.onClick(deviceItem, dialog)
+ verify(cachedDevice).disconnect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedDevice.address,
+ DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_connectedOtherDevice_disconnect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(deviceItem.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
+ actionInteractorImpl.onClick(deviceItem, dialog)
+ verify(cachedDevice).disconnect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(cachedDevice.address, DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_saved_connect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(deviceItem.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
+ actionInteractorImpl.onClick(deviceItem, dialog)
+ verify(cachedDevice).connect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(cachedDevice.address, DeviceItemType.SAVED_BLUETOOTH_DEVICE)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
new file mode 100644
index 000000000000..e8e37bc81866
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bluetooth.qsdialog
+
+import com.android.internal.logging.uiEventLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.bluetoothTileDialogLogger: BluetoothTileDialogLogger by Kosmos.Fixture { mock {} }
+
+val Kosmos.deviceItemActionInteractor: DeviceItemActionInteractor by
+ Kosmos.Fixture {
+ DeviceItemActionInteractorImpl(
+ testDispatcher,
+ bluetoothTileDialogLogger,
+ uiEventLogger,
+ )
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
index daf4a3cbb9de..2b4f9503f371 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
@@ -23,7 +23,6 @@ import android.media.AudioManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.SysuiTestCase
@@ -39,7 +38,6 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@@ -71,8 +69,6 @@ class DeviceItemInteractorTest : SysuiTestCase() {
@Mock private lateinit var localBluetoothManager: LocalBluetoothManager
- @Mock private lateinit var uiEventLogger: UiEventLogger
-
@Mock private lateinit var logger: BluetoothTileDialogLogger
private val fakeSystemClock = FakeSystemClock()
@@ -94,7 +90,6 @@ class DeviceItemInteractorTest : SysuiTestCase() {
adapter,
localBluetoothManager,
fakeSystemClock,
- uiEventLogger,
logger,
testScope.backgroundScope,
dispatcher
@@ -218,61 +213,6 @@ class DeviceItemInteractorTest : SysuiTestCase() {
}
}
- @Test
- fun testUpdateDeviceItemOnClick_connectedMedia_setActive() {
- testScope.runTest {
- `when`(deviceItem1.type).thenReturn(DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
-
- interactor.updateDeviceItemOnClick(deviceItem1)
-
- verify(cachedDevice1).setActive()
- verify(logger)
- .logDeviceClick(
- cachedDevice1.address,
- DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE
- )
- }
- }
-
- @Test
- fun testUpdateDeviceItemOnClick_activeMedia_disconnect() {
- testScope.runTest {
- `when`(deviceItem1.type).thenReturn(DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
-
- interactor.updateDeviceItemOnClick(deviceItem1)
-
- verify(cachedDevice1).disconnect()
- verify(logger)
- .logDeviceClick(cachedDevice1.address, DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
- }
- }
-
- @Test
- fun testUpdateDeviceItemOnClick_connectedOtherDevice_disconnect() {
- testScope.runTest {
- `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
-
- interactor.updateDeviceItemOnClick(deviceItem1)
-
- verify(cachedDevice1).disconnect()
- verify(logger)
- .logDeviceClick(cachedDevice1.address, DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
- }
- }
-
- @Test
- fun testUpdateDeviceItemOnClick_saved_connect() {
- testScope.runTest {
- `when`(deviceItem1.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
-
- interactor.updateDeviceItemOnClick(deviceItem1)
-
- verify(cachedDevice1).connect()
- verify(logger)
- .logDeviceClick(cachedDevice1.address, DeviceItemType.SAVED_BLUETOOTH_DEVICE)
- }
- }
-
private fun createFactory(
isFilterMatchFunc: (CachedBluetoothDevice) -> Boolean,
deviceItem: DeviceItem
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarterTest.kt
new file mode 100644
index 000000000000..05a2ca20037b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarterTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.ui
+
+import android.content.Intent
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyboard.shortcut.fakeShortcutHelperStartActivity
+import com.android.systemui.keyboard.shortcut.shortcutHelperActivityStarter
+import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
+import com.android.systemui.keyboard.shortcut.ui.view.ShortcutHelperActivity
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class ShortcutHelperActivityStarterTest : SysuiTestCase() {
+
+ private val kosmos =
+ Kosmos().also {
+ it.testCase = this
+ it.testDispatcher = UnconfinedTestDispatcher()
+ }
+
+ private val testScope = kosmos.testScope
+ private val testHelper = kosmos.shortcutHelperTestHelper
+ private val fakeStartActivity = kosmos.fakeShortcutHelperStartActivity
+ private val starter = kosmos.shortcutHelperActivityStarter
+
+ @Test
+ fun start_doesNotStartByDefault() =
+ testScope.runTest {
+ starter.start()
+
+ assertThat(fakeStartActivity.startIntents).isEmpty()
+ }
+
+ @Test
+ fun start_onToggle_startsActivity() =
+ testScope.runTest {
+ starter.start()
+
+ testHelper.toggle(deviceId = 456)
+
+ verifyShortcutHelperActivityStarted()
+ }
+
+ @Test
+ fun start_onToggle_multipleTimesStartsActivityOnlyWhenNotStarted() =
+ testScope.runTest {
+ starter.start()
+
+ testHelper.toggle(deviceId = 456)
+ testHelper.toggle(deviceId = 456)
+ testHelper.toggle(deviceId = 456)
+ testHelper.toggle(deviceId = 456)
+
+ verifyShortcutHelperActivityStarted(numTimes = 2)
+ }
+
+ @Test
+ fun start_onRequestShowShortcuts_startsActivity() =
+ testScope.runTest {
+ starter.start()
+
+ testHelper.showFromActivity()
+
+ verifyShortcutHelperActivityStarted()
+ }
+
+ @Test
+ fun start_onRequestShowShortcuts_multipleTimes_startsActivityOnlyOnce() =
+ testScope.runTest {
+ starter.start()
+
+ testHelper.showFromActivity()
+ testHelper.showFromActivity()
+ testHelper.showFromActivity()
+
+ verifyShortcutHelperActivityStarted(numTimes = 1)
+ }
+
+ @Test
+ fun start_onRequestShowShortcuts_multipleTimes_startsActivityOnlyWhenNotStarted() =
+ testScope.runTest {
+ starter.start()
+
+ testHelper.hideFromActivity()
+ testHelper.hideForSystem()
+ testHelper.toggle(deviceId = 987)
+ testHelper.showFromActivity()
+ testHelper.hideFromActivity()
+ testHelper.hideForSystem()
+ testHelper.toggle(deviceId = 456)
+ testHelper.showFromActivity()
+
+ verifyShortcutHelperActivityStarted(numTimes = 2)
+ }
+
+ private fun verifyShortcutHelperActivityStarted(numTimes: Int = 1) {
+ assertThat(fakeStartActivity.startIntents).hasSize(numTimes)
+ fakeStartActivity.startIntents.forEach { intent ->
+ assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK)
+ assertThat(intent.filterEquals(Intent(context, ShortcutHelperActivity::class.java)))
+ .isTrue()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
new file mode 100644
index 000000000000..86533086f67a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
+import com.android.systemui.keyboard.shortcut.shortcutHelperViewModel
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class ShortcutHelperViewModelTest : SysuiTestCase() {
+
+ private val kosmos =
+ Kosmos().also {
+ it.testCase = this
+ it.testDispatcher = UnconfinedTestDispatcher()
+ }
+
+ private val testScope = kosmos.testScope
+ private val testHelper = kosmos.shortcutHelperTestHelper
+
+ private val viewModel = kosmos.shortcutHelperViewModel
+
+ @Test
+ fun shouldShow_falseByDefault() =
+ testScope.runTest {
+ val shouldShow by collectLastValue(viewModel.shouldShow)
+
+ assertThat(shouldShow).isFalse()
+ }
+
+ @Test
+ fun shouldShow_trueAfterShowRequested() =
+ testScope.runTest {
+ val shouldShow by collectLastValue(viewModel.shouldShow)
+
+ testHelper.showFromActivity()
+
+ assertThat(shouldShow).isTrue()
+ }
+
+ @Test
+ fun shouldShow_trueAfterToggleRequested() =
+ testScope.runTest {
+ val shouldShow by collectLastValue(viewModel.shouldShow)
+
+ testHelper.toggle(deviceId = 123)
+
+ assertThat(shouldShow).isTrue()
+ }
+
+ @Test
+ fun shouldShow_falseAfterToggleTwice() =
+ testScope.runTest {
+ val shouldShow by collectLastValue(viewModel.shouldShow)
+
+ testHelper.toggle(deviceId = 123)
+ testHelper.toggle(deviceId = 123)
+
+ assertThat(shouldShow).isFalse()
+ }
+
+ @Test
+ fun shouldShow_falseAfterViewDestroyed() =
+ testScope.runTest {
+ val shouldShow by collectLastValue(viewModel.shouldShow)
+
+ testHelper.toggle(deviceId = 567)
+ viewModel.onUserLeave()
+
+ assertThat(shouldShow).isFalse()
+ }
+
+ @Test
+ fun shouldShow_doesNotEmitDuplicateValues() =
+ testScope.runTest {
+ val shouldShowValues by collectValues(viewModel.shouldShow)
+
+ testHelper.hideForSystem()
+ testHelper.toggle(deviceId = 987)
+ testHelper.showFromActivity()
+ viewModel.onUserLeave()
+ testHelper.hideFromActivity()
+ testHelper.hideForSystem()
+ testHelper.toggle(deviceId = 456)
+ testHelper.showFromActivity()
+
+ assertThat(shouldShowValues).containsExactly(false, true, false, true).inOrder()
+ }
+
+ @Test
+ fun shouldShow_emitsLatestValueToNewSubscribers() =
+ testScope.runTest {
+ val shouldShow by collectLastValue(viewModel.shouldShow)
+
+ testHelper.showFromActivity()
+
+ val shouldShowNew by collectLastValue(viewModel.shouldShow)
+ assertThat(shouldShowNew).isEqualTo(shouldShow)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
index f5b5261de139..bcaad01f1a24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
@@ -19,20 +19,24 @@
package com.android.systemui.keyguard.data.repository
+import android.os.fakeExecutorHandler
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
-import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
+import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.util.ThreadAssert
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -46,32 +50,31 @@ import org.mockito.MockitoAnnotations
class KeyguardBlueprintRepositoryTest : SysuiTestCase() {
private lateinit var underTest: KeyguardBlueprintRepository
@Mock lateinit var configurationRepository: ConfigurationRepository
+ @Mock lateinit var defaultLockscreenBlueprint: DefaultKeyguardBlueprint
@Mock lateinit var threadAssert: ThreadAssert
-
private val testScope = TestScope(StandardTestDispatcher())
private val kosmos: Kosmos = testKosmos()
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- underTest = kosmos.keyguardBlueprintRepository
- }
-
- @Test
- fun testApplyBlueprint_DefaultLayout() {
- testScope.runTest {
- val blueprint by collectLastValue(underTest.blueprint)
- underTest.applyBlueprint(DefaultKeyguardBlueprint.DEFAULT)
- assertThat(blueprint).isEqualTo(kosmos.defaultKeyguardBlueprint)
+ with(kosmos) {
+ whenever(defaultLockscreenBlueprint.id).thenReturn(DEFAULT)
+ underTest =
+ KeyguardBlueprintRepository(
+ setOf(defaultLockscreenBlueprint),
+ fakeExecutorHandler,
+ threadAssert,
+ )
}
}
@Test
- fun testApplyBlueprint_SplitShadeLayout() {
+ fun testApplyBlueprint_DefaultLayout() {
testScope.runTest {
val blueprint by collectLastValue(underTest.blueprint)
- underTest.applyBlueprint(SplitShadeKeyguardBlueprint.ID)
- assertThat(blueprint).isEqualTo(kosmos.splitShadeBlueprint)
+ underTest.applyBlueprint(defaultLockscreenBlueprint)
+ assertThat(blueprint).isEqualTo(defaultLockscreenBlueprint)
}
}
@@ -80,22 +83,33 @@ class KeyguardBlueprintRepositoryTest : SysuiTestCase() {
testScope.runTest {
val blueprint by collectLastValue(underTest.blueprint)
underTest.refreshBlueprint()
- assertThat(blueprint).isEqualTo(kosmos.defaultKeyguardBlueprint)
+ assertThat(blueprint).isEqualTo(defaultLockscreenBlueprint)
}
}
@Test
- fun testTransitionToDefaultLayout_validId() {
- assertThat(underTest.applyBlueprint(DefaultKeyguardBlueprint.DEFAULT)).isTrue()
- }
-
- @Test
- fun testTransitionToSplitShadeLayout_validId() {
- assertThat(underTest.applyBlueprint(SplitShadeKeyguardBlueprint.ID)).isTrue()
+ fun testTransitionToLayout_validId() {
+ assertThat(underTest.applyBlueprint(DEFAULT)).isTrue()
}
@Test
fun testTransitionToLayout_invalidId() {
assertThat(underTest.applyBlueprint("abc")).isFalse()
}
+
+ @Test
+ fun testTransitionToSameBlueprint_refreshesBlueprint() =
+ with(kosmos) {
+ testScope.runTest {
+ val transition by collectLastValue(underTest.refreshTransition)
+ fakeExecutor.runAllReady()
+ runCurrent()
+
+ underTest.applyBlueprint(defaultLockscreenBlueprint)
+ fakeExecutor.runAllReady()
+ runCurrent()
+
+ assertThat(transition).isNotNull()
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
index 9ccf2121b8d2..f32e7757328f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
@@ -274,4 +274,27 @@ class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
runCurrent()
assertThat(isAnimatingSurface).isFalse()
}
+
+ @Test
+ fun notificationLaunchFalse_isAnimatingSurfaceFalse() =
+ testScope.runTest {
+ val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ transitionState = TransitionState.FINISHED,
+ )
+ )
+ kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
+ runCurrent()
+ assertThat(isAnimatingSurface).isFalse()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
index 8a0613f9b010..dbf6a29073a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
@@ -66,19 +66,25 @@ class KeyguardBlueprintCommandListenerTest : SysuiTestCase() {
fun testHelp() {
command().execute(pw, listOf("help"))
verify(pw, atLeastOnce()).println(anyString())
- verify(keyguardBlueprintInteractor, never()).transitionOrRefreshBlueprint(anyString())
+ verify(keyguardBlueprintInteractor, never()).transitionToBlueprint(anyString())
}
@Test
fun testBlank() {
command().execute(pw, listOf())
verify(pw, atLeastOnce()).println(anyString())
- verify(keyguardBlueprintInteractor, never()).transitionOrRefreshBlueprint(anyString())
+ verify(keyguardBlueprintInteractor, never()).transitionToBlueprint(anyString())
}
@Test
fun testValidArg() {
command().execute(pw, listOf("fake"))
- verify(keyguardBlueprintInteractor).transitionOrRefreshBlueprint("fake")
+ verify(keyguardBlueprintInteractor).transitionToBlueprint("fake")
+ }
+
+ @Test
+ fun testValidArg_Int() {
+ command().execute(pw, listOf("1"))
+ verify(keyguardBlueprintInteractor).transitionToBlueprint(1)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index b5ef8c26a7ce..db11c3e89160 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -500,6 +500,42 @@ class QSTileViewImplTest : SysuiTestCase() {
)
}
+ @Test
+ fun onActivityLaunchAnimationEnd_onFreshTile_longPressPropertiesAreReset() {
+ // WHEN an activity launch animation ends on a fresh tile
+ tileView.onActivityLaunchAnimationEnd()
+
+ // THEN the tile's long-press effect properties are reset by default
+ assertThat(tileView.haveLongPressPropertiesBeenReset).isTrue()
+ }
+
+ @Test
+ fun onUpdateLongPressEffectProperties_duringLongPressEffect_propertiesAreNotReset() {
+ // GIVEN a state that supports long-press
+ val state = QSTile.State()
+ tileView.changeState(state)
+
+ // WHEN the long-press effect is updating the properties
+ tileView.updateLongPressEffectProperties(1f)
+
+ // THEN the tile's long-press effect properties haven't reset
+ assertThat(tileView.haveLongPressPropertiesBeenReset).isFalse()
+ }
+
+ @Test
+ fun onActivityLaunchAnimationEnd_afterLongPressEffect_longPressPropertiesAreReset() {
+ // GIVEN a state that supports long-press and the long-press effect updating
+ val state = QSTile.State()
+ tileView.changeState(state)
+ tileView.updateLongPressEffectProperties(1f)
+
+ // WHEN an activity launch animation ends on a fresh tile
+ tileView.onActivityLaunchAnimationEnd()
+
+ // THEN the tile's long-press effect properties are reset
+ assertThat(tileView.haveLongPressPropertiesBeenReset).isTrue()
+ }
+
class FakeTileView(
context: Context,
collapsed: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
index 0f3714385725..bf7d909380df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
@@ -69,8 +69,9 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
@Before
fun setUp() {
- whenever(controllerFactory.create(eq(0), any())).thenReturn(controller0)
- whenever(controllerFactory.create(eq(1), any())).thenReturn(controller1)
+ whenever(controllerFactory.create(any(), any())).thenAnswer {
+ if (it.getArgument<Display>(0).displayId == 0) controller0 else controller1
+ }
whenever(notificationControllerFactory.create(eq(0))).thenReturn(notificationsController0)
whenever(notificationControllerFactory.create(eq(1))).thenReturn(notificationsController1)
}
@@ -78,12 +79,14 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
@Test
fun executeScreenshots_severalDisplays_callsControllerForEachOne() =
testScope.runTest {
- setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
+ val internalDisplay = display(TYPE_INTERNAL, id = 0)
+ val externalDisplay = display(TYPE_EXTERNAL, id = 1)
+ setDisplays(internalDisplay, externalDisplay)
val onSaved = { _: Uri? -> }
screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback)
- verify(controllerFactory).create(eq(0), any())
- verify(controllerFactory).create(eq(1), any())
+ verify(controllerFactory).create(eq(internalDisplay), any())
+ verify(controllerFactory).create(eq(externalDisplay), any())
val capturer = ArgumentCaptor<ScreenshotData>()
@@ -107,7 +110,9 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
@Test
fun executeScreenshots_providedImageType_callsOnlyDefaultDisplayController() =
testScope.runTest {
- setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1))
+ val internalDisplay = display(TYPE_INTERNAL, id = 0)
+ val externalDisplay = display(TYPE_EXTERNAL, id = 1)
+ setDisplays(internalDisplay, externalDisplay)
val onSaved = { _: Uri? -> }
screenshotExecutor.executeScreenshots(
createScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE),
@@ -115,8 +120,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
callback
)
- verify(controllerFactory).create(eq(0), any())
- verify(controllerFactory, never()).create(eq(1), any())
+ verify(controllerFactory).create(eq(internalDisplay), any())
+ verify(controllerFactory, never()).create(eq(externalDisplay), any())
val capturer = ArgumentCaptor<ScreenshotData>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
index d44e26c266fc..e32086b79918 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
@@ -34,20 +34,21 @@ class ScreenshotViewModelTest {
assertThat(viewModel.actions.value).isEmpty()
- viewModel.addAction(appearance, onclick)
+ viewModel.addAction(appearance, true, onclick)
assertThat(viewModel.actions.value).hasSize(1)
val added = viewModel.actions.value[0]
assertThat(added.appearance).isEqualTo(appearance)
assertThat(added.onClicked).isEqualTo(onclick)
+ assertThat(added.showDuringEntrance).isTrue()
}
@Test
fun testRemoveAction() {
val viewModel = ScreenshotViewModel(accessibilityManager)
- val firstId = viewModel.addAction(ActionButtonAppearance(null, "", ""), {})
- val secondId = viewModel.addAction(appearance, onclick)
+ val firstId = viewModel.addAction(ActionButtonAppearance(null, "", ""), false, {})
+ val secondId = viewModel.addAction(appearance, false, onclick)
assertThat(viewModel.actions.value).hasSize(2)
assertThat(firstId).isNotEqualTo(secondId)
@@ -58,13 +59,14 @@ class ScreenshotViewModelTest {
val remaining = viewModel.actions.value[0]
assertThat(remaining.appearance).isEqualTo(appearance)
+ assertThat(remaining.showDuringEntrance).isFalse()
assertThat(remaining.onClicked).isEqualTo(onclick)
}
@Test
fun testUpdateActionAppearance() {
val viewModel = ScreenshotViewModel(accessibilityManager)
- val id = viewModel.addAction(appearance, onclick)
+ val id = viewModel.addAction(appearance, false, onclick)
val otherAppearance = ActionButtonAppearance(null, "Other", "Other")
viewModel.updateActionAppearance(id, otherAppearance)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 99204e75e5a3..537049c7b957 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -18,7 +18,7 @@ package com.android.systemui.shade
import android.graphics.Rect
import android.os.PowerManager
-import android.platform.test.flag.junit.FlagsParameterization
+import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.MotionEvent
@@ -27,6 +27,7 @@ import android.widget.FrameLayout
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
@@ -42,16 +43,11 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.util.CommunalColors
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.sceneDataSourceDelegator
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -59,6 +55,7 @@ import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -71,14 +68,12 @@ import org.mockito.Mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4
-import platform.test.runner.parameterized.Parameters
@ExperimentalCoroutinesApi
-@RunWith(ParameterizedAndroidJunit4::class)
+@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
-class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : SysuiTestCase() {
+class GlanceableHubContainerControllerTest : SysuiTestCase() {
private val kosmos: Kosmos =
testKosmos().apply {
// UnconfinedTestDispatcher makes testing simpler due to CommunalInteractor flows using
@@ -100,10 +95,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
private lateinit var communalRepository: FakeCommunalRepository
private lateinit var underTest: GlanceableHubContainerController
- init {
- mSetFlagsRule.setFlagsParameterization(flags!!)
- }
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -127,7 +118,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
communalInteractor,
communalViewModel,
dialogFactory,
- keyguardTransitionInteractor,
keyguardInteractor,
shadeInteractor,
powerManager,
@@ -170,7 +160,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
communalInteractor,
communalViewModel,
dialogFactory,
- keyguardTransitionInteractor,
keyguardInteractor,
shadeInteractor,
powerManager,
@@ -216,13 +205,39 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
}
@Test
+ fun onTouchEvent_communalTransitioning_interceptsTouches() =
+ with(kosmos) {
+ testScope.runTest {
+ // Communal is opening.
+ communalRepository.setTransitionState(
+ flowOf(
+ ObservableTransitionState.Transition(
+ fromScene = CommunalScenes.Blank,
+ toScene = CommunalScenes.Communal,
+ currentScene = flowOf(CommunalScenes.Blank),
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true)
+ )
+ )
+ )
+ testableLooper.processAllMessages()
+
+ // Touch events are intercepted.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ // User activity sent to PowerManager.
+ verify(powerManager).userActivity(any(), any(), any())
+ }
+ }
+
+ @Test
fun onTouchEvent_communalOpen_interceptsTouches() =
with(kosmos) {
testScope.runTest {
// Communal is open.
goToScene(CommunalScenes.Communal)
- // Touch events are intercepted outside of any gesture areas.
+ // Touch events are intercepted.
assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
// User activity sent to PowerManager.
verify(powerManager).userActivity(any(), any(), any())
@@ -289,7 +304,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
communalInteractor,
communalViewModel,
dialogFactory,
- keyguardTransitionInteractor,
keyguardInteractor,
shadeInteractor,
powerManager,
@@ -309,7 +323,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
communalInteractor,
communalViewModel,
dialogFactory,
- keyguardTransitionInteractor,
keyguardInteractor,
shadeInteractor,
powerManager,
@@ -501,13 +514,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
}
private fun goToScene(scene: SceneKey) {
- if (SceneContainerFlag.isEnabled) {
- if (scene == CommunalScenes.Communal) {
- kosmos.sceneInteractor.changeScene(Scenes.Communal, "test")
- } else {
- kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "test")
- }
- }
communalRepository.changeScene(scene)
testableLooper.processAllMessages()
}
@@ -536,11 +542,5 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu
MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, CONTAINER_WIDTH.toFloat(), 0f, 0)
private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
private val UP_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
-
- @JvmStatic
- @Parameters(name = "{0}")
- fun getParams(): List<FlagsParameterization> {
- return FlagsParameterization.allCombinationsOf().andSceneContainer()
- }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 6b57f6e06bda..e1cdda440976 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -428,6 +428,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo
public void testOnTouchEvent_expansionResumesAfterBriefTouch() {
mFalsingManager.setIsClassifierEnabled(true);
mFalsingManager.setIsFalseTouch(false);
+ mNotificationPanelViewController.setForceFlingAnimationForTest(true);
// Start shade collapse with swipe up
onTouchEvent(MotionEvent.obtain(0L /* downTime */,
0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */,
@@ -456,6 +457,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo
// fling should still be called after a touch that does not exceed touch slop
assertThat(mNotificationPanelViewController.isClosing()).isTrue();
assertThat(mNotificationPanelViewController.isFlinging()).isTrue();
+ mNotificationPanelViewController.setForceFlingAnimationForTest(false);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 112829af2068..a867b0f7df00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -17,12 +17,15 @@
package com.android.systemui.shade
import android.content.Context
+import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.flag.junit.FlagsParameterization
+import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
+import android.view.ViewTreeObserver
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.LegacyLockIconViewController
@@ -72,7 +75,6 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
-import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow
@@ -80,12 +82,12 @@ import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.atLeast
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
@@ -93,6 +95,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
+import java.util.Optional
import org.mockito.Mockito.`when` as whenever
@OptIn(ExperimentalCoroutinesApi::class)
@@ -152,6 +155,7 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) :
private lateinit var underTest: NotificationShadeWindowViewController
private lateinit var testScope: TestScope
+ private lateinit var testableLooper: TestableLooper
private lateinit var featureFlagsClassic: FakeFeatureFlagsClassic
@@ -181,6 +185,7 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) :
mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES)
testScope = TestScope()
+ testableLooper = TestableLooper.get(this)
falsingCollector = FalsingCollectorFake()
fakeClock = FakeSystemClock()
underTest =
@@ -407,6 +412,7 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) :
}
@Test
+ @DisableSceneContainer
fun handleDispatchTouchEvent_glanceableHubIntercepts_returnsTrue() {
whenever(mGlanceableHubContainerController.onTouchEvent(DOWN_EVENT)).thenReturn(true)
underTest.setStatusBarViewController(phoneStatusBarViewController)
@@ -559,29 +565,42 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) :
}
@Test
- @Ignore("b/321332798")
+ @DisableSceneContainer
fun setsUpCommunalHubLayout_whenFlagEnabled() {
whenever(mGlanceableHubContainerController.communalAvailable())
- .thenReturn(MutableStateFlow(true))
+ .thenReturn(MutableStateFlow(true))
- val mockCommunalView = mock(View::class.java)
+ val communalView = View(context)
whenever(mGlanceableHubContainerController.initView(any<Context>()))
- .thenReturn(mockCommunalView)
+ .thenReturn(communalView)
val mockCommunalPlaceholder = mock(View::class.java)
val fakeViewIndex = 20
whenever(view.findViewById<View>(R.id.communal_ui_stub)).thenReturn(mockCommunalPlaceholder)
whenever(view.indexOfChild(mockCommunalPlaceholder)).thenReturn(fakeViewIndex)
whenever(view.context).thenReturn(context)
+ whenever(view.viewTreeObserver).thenReturn(mock(ViewTreeObserver::class.java))
underTest.setupCommunalHubLayout()
- // Communal view added as a child of the container at the proper index, the stub is removed.
- verify(view).removeView(mockCommunalPlaceholder)
- verify(view).addView(eq(mockCommunalView), eq(fakeViewIndex))
+ // Simluate attaching the view so flow collection starts.
+ val onAttachStateChangeListenerArgumentCaptor = ArgumentCaptor.forClass(
+ View.OnAttachStateChangeListener::class.java
+ )
+ verify(view, atLeast(1)).addOnAttachStateChangeListener(
+ onAttachStateChangeListenerArgumentCaptor.capture()
+ )
+ for (listener in onAttachStateChangeListenerArgumentCaptor.allValues) {
+ listener.onViewAttachedToWindow(view)
+ }
+ testableLooper.processAllMessages()
+
+ // Communal view added as a child of the container at the proper index.
+ verify(view).addView(eq(communalView), eq(fakeViewIndex))
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_COMMUNAL_HUB)
fun doesNotSetupCommunalHubLayout_whenFlagDisabled() {
whenever(mGlanceableHubContainerController.communalAvailable())
.thenReturn(MutableStateFlow(false))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
index 158f38d48197..347620a1631a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
@@ -19,12 +19,13 @@
package com.android.systemui.statusbar.notification.footer.ui.viewmodel
import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
-import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -33,7 +34,7 @@ import com.android.systemui.power.data.repository.powerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.res.R
-import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.shared.settings.data.repository.fakeSecureSettingsRepository
import com.android.systemui.statusbar.notification.collection.render.NotifStats
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
@@ -45,13 +46,16 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
-@RunWith(AndroidTestingRunner::class)
+@RunWith(ParameterizedAndroidJunit4::class)
@SmallTest
@EnableFlags(FooterViewRefactor.FLAG_NAME)
-class FooterViewModelTest : SysuiTestCase() {
+class FooterViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
@@ -59,11 +63,29 @@ class FooterViewModelTest : SysuiTestCase() {
private val testScope = kosmos.testScope
private val activeNotificationListRepository = kosmos.activeNotificationListRepository
private val fakeKeyguardRepository = kosmos.fakeKeyguardRepository
- private val shadeRepository = kosmos.shadeRepository
private val powerRepository = kosmos.powerRepository
private val fakeSecureSettingsRepository = kosmos.fakeSecureSettingsRepository
- val underTest = kosmos.footerViewModel
+ private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
+
+ private lateinit var underTest: FooterViewModel
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags!!)
+ }
+
+ @Before
+ fun setup() {
+ underTest = kosmos.footerViewModel
+ }
@Test
fun messageVisible_whenFilteredNotifications() =
@@ -146,11 +168,9 @@ class FooterViewModelTest : SysuiTestCase() {
val visible by collectLastValue(underTest.clearAllButton.isVisible)
runCurrent()
- // WHEN shade is expanded
+ // WHEN shade is expanded AND QS not expanded
fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
- shadeRepository.setLegacyShadeExpansion(1f)
- // AND QS not expanded
- shadeRepository.setQsExpansion(0f)
+ shadeTestUtil.setShadeAndQsExpansion(1f, 0f)
// AND device is awake
powerRepository.updateWakefulness(
rawState = WakefulnessState.AWAKE,
@@ -182,9 +202,9 @@ class FooterViewModelTest : SysuiTestCase() {
// WHEN shade is collapsed
fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
- shadeRepository.setLegacyShadeExpansion(0f)
+ shadeTestUtil.setShadeExpansion(0f)
// AND QS not expanded
- shadeRepository.setQsExpansion(0f)
+ shadeTestUtil.setQsExpansion(0f)
// AND device is awake
powerRepository.updateWakefulness(
rawState = WakefulnessState.AWAKE,
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 a66a1360f8f8..f262df1d875a 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
@@ -24,6 +24,7 @@ import static com.android.systemui.statusbar.notification.stack.NotificationStac
import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -43,6 +44,7 @@ import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
@@ -51,11 +53,14 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.ExpandHelper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.DisableSceneContainer;
+import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -171,6 +176,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private NotificationListViewBinder mViewBinder;
@Mock
private SensitiveNotificationProtectionController mSensitiveNotificationProtectionController;
+ @Mock private ExpandHelper mExpandHelper;
@Captor
private ArgumentCaptor<Runnable> mSensitiveStateListenerArgumentCaptor;
@@ -895,6 +901,50 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
verify(mSensitiveNotificationProtectionController).registerSensitiveStateListener(any());
}
+ @Test
+ @EnableSceneContainer
+ public void onTouchEvent_stopExpandingNotification_sceneContainerEnabled() {
+ boolean touchHandled = stopExpandingNotification();
+
+ verify(mNotificationStackScrollLayout).startOverscrollAfterExpanding();
+ verify(mNotificationStackScrollLayout, never()).dispatchDownEventToScroller(any());
+ assertTrue(touchHandled);
+ }
+
+ @Test
+ @DisableSceneContainer
+ public void onTouchEvent_stopExpandingNotification_sceneContainerDisabled() {
+ stopExpandingNotification();
+
+ verify(mNotificationStackScrollLayout, never()).startOverscrollAfterExpanding();
+ verify(mNotificationStackScrollLayout).dispatchDownEventToScroller(any());
+ }
+
+ private boolean stopExpandingNotification() {
+ when(mNotificationStackScrollLayout.getExpandHelper()).thenReturn(mExpandHelper);
+ when(mNotificationStackScrollLayout.getIsExpanded()).thenReturn(true);
+ when(mNotificationStackScrollLayout.getExpandedInThisMotion()).thenReturn(true);
+ when(mNotificationStackScrollLayout.isExpandingNotification()).thenReturn(true);
+
+ when(mExpandHelper.onTouchEvent(any())).thenAnswer(i -> {
+ when(mNotificationStackScrollLayout.isExpandingNotification()).thenReturn(false);
+ return false;
+ });
+
+ initController(/* viewIsAttached= */ true);
+ NotificationStackScrollLayoutController.TouchHandler touchHandler =
+ mController.getTouchHandler();
+
+ return touchHandler.onTouchEvent(MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 0,
+ MotionEvent.ACTION_DOWN,
+ 0,
+ 0,
+ /* metaState= */ 0
+ ));
+ }
+
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 939d0556e347..0c0a2a59d9bc 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
@@ -207,6 +207,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
.thenReturn(mNotificationRoundnessManager);
mStackScroller.setController(mStackScrollLayoutController);
mStackScroller.setShelf(mNotificationShelf);
+ when(mStackScroller.getExpandHelper()).thenReturn(mExpandHelper);
doNothing().when(mGroupExpansionManager).collapseGroups();
doNothing().when(mExpandHelper).cancelImmediately();
@@ -1139,6 +1140,14 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
assertFalse(mStackScroller.mHeadsUpAnimatingAway);
}
+ @Test
+ @EnableSceneContainer
+ public void finishExpanding_sceneContainerEnabled() {
+ mStackScroller.startOverscrollAfterExpanding();
+ verify(mStackScroller.getExpandHelper()).finishExpanding();
+ assertTrue(mStackScroller.getIsBeingDragged());
+ }
+
private MotionEvent captureTouchSentToSceneFramework() {
ArgumentCaptor<MotionEvent> captor = ArgumentCaptor.forClass(MotionEvent.class);
verify(mStackScrollLayoutController).sendTouchToSceneFramework(captor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 82725d656bb9..a6fb7187ff5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -394,8 +394,20 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
}
@Test
+ fun resetViewStates_shadeCollapsed_emptyShadeViewBecomesTransparent() {
+ ambientState.expansionFraction = 0f
+ stackScrollAlgorithm.initView(context)
+ hostView.removeAllViews()
+ hostView.addView(emptyShadeView)
+
+ stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+ assertThat(emptyShadeView.viewState.alpha).isEqualTo(0f)
+ }
+
+ @Test
fun resetViewStates_isOnKeyguard_emptyShadeViewBecomesOpaque() {
- ambientState.setStatusBarState(StatusBarState.SHADE)
+ ambientState.setStatusBarState(StatusBarState.KEYGUARD)
ambientState.fractionToShade = 0.25f
stackScrollAlgorithm.initView(context)
hostView.removeAllViews()
@@ -403,7 +415,8 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
- assertThat(emptyShadeView.viewState.alpha).isEqualTo(1f)
+ val expected = getContentAlpha(ambientState.fractionToShade)
+ assertThat(emptyShadeView.viewState.alpha).isEqualTo(expected)
}
@Test
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeOneHandedModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeOneHandedModeRepository.kt
new file mode 100644
index 000000000000..ac135afaebff
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeOneHandedModeRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeOneHandedModeRepository : OneHandedModeRepository {
+ private val userMap = mutableMapOf<Int, MutableStateFlow<Boolean>>()
+
+ override fun isEnabled(userHandle: UserHandle): StateFlow<Boolean> {
+ return getFlow(userHandle.identifier)
+ }
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean {
+ getFlow(userHandle.identifier).value = isEnabled
+ return true
+ }
+
+ /** initializes the flow if already not */
+ private fun getFlow(userId: Int): MutableStateFlow<Boolean> {
+ return userMap.getOrPut(userId) { MutableStateFlow(false) }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryKosmos.kt
new file mode 100644
index 000000000000..9ee200ab5532
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/OneHandedModeRepositoryKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeOneHandedModeRepository by Kosmos.Fixture { FakeOneHandedModeRepository() }
+val Kosmos.oneHandedModeRepository by Kosmos.Fixture { fakeOneHandedModeRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
index 2e2cf9a61a8c..0975687b4744 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
@@ -81,7 +81,8 @@ class FakePromptRepository : PromptRepository {
com.android.systemui.Flags.constraintBp() &&
!Utils.isBiometricAllowed(promptInfo) &&
Utils.isDeviceCredentialAllowed(promptInfo) &&
- promptInfo.contentView != null
+ promptInfo.contentView != null &&
+ !promptInfo.isContentViewMoreOptionsButtonUsed
_showBpWithoutIconForCredential.value = showBpForCredential && !hasCredentialViewShown
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
index 9f5c6b8faa38..d958bae7ae2a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
@@ -23,6 +23,7 @@ class FakeCommunalRepository(
) : CommunalRepository {
override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) {
this.currentScene.value = toScene
+ this._transitionState.value = flowOf(ObservableTransitionState.Idle(toScene))
}
private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/FakeShortcutHelperStartActivity.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/FakeShortcutHelperStartActivity.kt
new file mode 100644
index 000000000000..3190171b180d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/FakeShortcutHelperStartActivity.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut
+
+import android.content.Intent
+
+class FakeShortcutHelperStartActivity : (Intent) -> Unit {
+
+ val startIntents = mutableListOf<Intent>()
+
+ override fun invoke(intent: Intent) {
+ startIntents += intent
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
new file mode 100644
index 000000000000..38f2a56d317f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut
+
+import android.content.applicationContext
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperRepository
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperTestHelper
+import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperInteractor
+import com.android.systemui.keyboard.shortcut.ui.ShortcutHelperActivityStarter
+import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
+import com.android.systemui.keyguard.data.repository.fakeCommandQueue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+
+val Kosmos.shortcutHelperRepository by
+ Kosmos.Fixture { ShortcutHelperRepository(fakeCommandQueue, broadcastDispatcher) }
+
+val Kosmos.shortcutHelperTestHelper by
+ Kosmos.Fixture {
+ ShortcutHelperTestHelper(
+ shortcutHelperRepository,
+ applicationContext,
+ broadcastDispatcher,
+ fakeCommandQueue
+ )
+ }
+
+val Kosmos.shortcutHelperInteractor by
+ Kosmos.Fixture { ShortcutHelperInteractor(shortcutHelperRepository) }
+
+val Kosmos.shortcutHelperViewModel by
+ Kosmos.Fixture { ShortcutHelperViewModel(testDispatcher, shortcutHelperInteractor) }
+
+val Kosmos.fakeShortcutHelperStartActivity by Kosmos.Fixture { FakeShortcutHelperStartActivity() }
+
+val Kosmos.shortcutHelperActivityStarter by
+ Kosmos.Fixture {
+ ShortcutHelperActivityStarter(
+ applicationContext,
+ applicationCoroutineScope,
+ shortcutHelperViewModel,
+ fakeShortcutHelperStartActivity,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt
new file mode 100644
index 000000000000..772ce415a6e9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.data.repository
+
+import android.content.Context
+import android.content.Intent
+import com.android.systemui.broadcast.FakeBroadcastDispatcher
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue
+
+class ShortcutHelperTestHelper(
+ repo: ShortcutHelperRepository,
+ private val context: Context,
+ private val fakeBroadcastDispatcher: FakeBroadcastDispatcher,
+ private val fakeCommandQueue: FakeCommandQueue,
+) {
+
+ init {
+ repo.start()
+ }
+
+ fun hideFromActivity() {
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS)
+ )
+ }
+
+ fun showFromActivity() {
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS)
+ )
+ }
+
+ fun toggle(deviceId: Int) {
+ fakeCommandQueue.doForEachCallback { it.toggleKeyboardShortcutsMenu(deviceId) }
+ }
+
+ fun hideForSystem() {
+ fakeCommandQueue.doForEachCallback { it.dismissKeyboardShortcutsMenu() }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index a242368d1ee1..2fe7438bcc77 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -40,12 +40,21 @@ import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
-/** Fake implementation of [KeyguardTransitionRepository] */
+/**
+ * Fake implementation of [KeyguardTransitionRepository].
+ *
+ * By default, will be seeded with a transition from OFF -> LOCKSCREEN, which is the most common
+ * case. If the lockscreen is disabled, or we're in setup wizard, the repository will initialize
+ * with OFF -> GONE. Construct with initInLockscreen = false if your test requires this behavior.
+ */
@SysUISingleton
-class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitionRepository {
+class FakeKeyguardTransitionRepository(
+ private val initInLockscreen: Boolean = true,
+) : KeyguardTransitionRepository {
private val _transitions =
MutableSharedFlow<TransitionStep>(replay = 3, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override val transitions: SharedFlow<TransitionStep> = _transitions
+ @Inject constructor() : this(initInLockscreen = true)
private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
MutableStateFlow(
@@ -59,8 +68,21 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio
override var currentTransitionInfoInternal = _currentTransitionInfo.asStateFlow()
init {
- // Seed the fake repository with the same initial steps the actual repository uses.
- KeyguardTransitionRepositoryImpl.initialTransitionSteps.forEach { _transitions.tryEmit(it) }
+ // Seed with a FINISHED transition in OFF, same as the real repository.
+ _transitions.tryEmit(
+ TransitionStep(
+ KeyguardState.OFF,
+ KeyguardState.OFF,
+ 1f,
+ TransitionState.FINISHED,
+ )
+ )
+
+ if (initInLockscreen) {
+ tryEmitInitialStepsFromOff(KeyguardState.LOCKSCREEN)
+ } else {
+ tryEmitInitialStepsFromOff(KeyguardState.OFF)
+ }
}
/**
@@ -223,6 +245,32 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio
return if (info.animator == null) UUID.randomUUID() else null
}
+ override suspend fun emitInitialStepsFromOff(to: KeyguardState) {
+ tryEmitInitialStepsFromOff(to)
+ }
+
+ private fun tryEmitInitialStepsFromOff(to: KeyguardState) {
+ _transitions.tryEmit(
+ TransitionStep(
+ KeyguardState.OFF,
+ to,
+ 0f,
+ TransitionState.STARTED,
+ ownerName = "KeyguardTransitionRepository(boot)",
+ )
+ )
+
+ _transitions.tryEmit(
+ TransitionStep(
+ KeyguardState.OFF,
+ to,
+ 1f,
+ TransitionState.FINISHED,
+ ownerName = "KeyguardTransitionRepository(boot)",
+ ),
+ )
+ }
+
override fun updateTransition(
transitionId: UUID,
@FloatRange(from = 0.0, to = 1.0) value: Float,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractorKosmos.kt
new file mode 100644
index 000000000000..7d8d33f7dd11
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractorKosmos.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
+
+val Kosmos.keyguardTransitionBootInteractor: KeyguardTransitionBootInteractor by
+ Kosmos.Fixture {
+ KeyguardTransitionBootInteractor(
+ scope = applicationCoroutineScope,
+ deviceEntryInteractor = deviceEntryInteractor,
+ deviceProvisioningInteractor = deviceProvisioningInteractor,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
+ repository = keyguardTransitionRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/onehanded/OneHandedModeTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/onehanded/OneHandedModeTileKosmos.kt
new file mode 100644
index 000000000000..d9c0361c8dc9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/onehanded/OneHandedModeTileKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.onehanded
+
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+
+val Kosmos.qsOneHandedModeTileConfig by
+ Kosmos.Fixture { QSAccessibilityModule.provideOneHandedTileConfig(qsEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
index ebe591b32536..d82286fd3569 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
@@ -32,6 +32,7 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.startable.SceneContainerStartable
+import com.android.systemui.scene.session.shared.shadeSessionStorage
import com.android.systemui.scene.shared.logger.sceneLogger
import com.android.systemui.settings.displayTracker
import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -65,5 +66,6 @@ val Kosmos.sceneContainerStartable by Fixture {
shadeInteractor = shadeInteractor,
uiEventLogger = uiEventLogger,
sceneBackInteractor = sceneBackInteractor,
+ shadeSessionStorage = shadeSessionStorage,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/session/shared/SessionStorageKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/session/shared/SessionStorageKosmos.kt
new file mode 100644
index 000000000000..0bee9378b7c4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/session/shared/SessionStorageKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.session.shared
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+var Kosmos.shadeSessionStorage by Fixture { SessionStorage() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
index 59a01cbedc5c..957a60f83134 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
@@ -42,6 +42,10 @@ class FakeSceneDataSource(
}
}
+ override fun snapToScene(toScene: SceneKey) {
+ changeScene(toScene)
+ }
+
/**
* Pauses scene changes.
*
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
index 59a5bb5360e3..38ede44efef6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
@@ -59,11 +59,23 @@ class ShadeTestUtil constructor(val delegate: ShadeTestUtilDelegate) {
delegate.setLockscreenShadeExpansion(lockscreenShadeExpansion)
}
- /** Sets whether the user is moving the shade with touch input. */
+ /** Sets whether the user is moving the shade with touch input on Lockscreen. */
fun setLockscreenShadeTracking(lockscreenShadeTracking: Boolean) {
delegate.assertFlagValid()
delegate.setLockscreenShadeTracking(lockscreenShadeTracking)
}
+
+ /** Sets whether the user is moving the shade with touch input. */
+ fun setTracking(tracking: Boolean) {
+ delegate.assertFlagValid()
+ delegate.setTracking(tracking)
+ }
+
+ /** Sets the shade to half collapsed with no touch input. */
+ fun programmaticCollapseShade() {
+ delegate.assertFlagValid()
+ delegate.programmaticCollapseShade()
+ }
}
/** Sets up shade state for tests for a specific value of the scene container flag. */
@@ -80,11 +92,17 @@ interface ShadeTestUtilDelegate {
/** Sets whether the user is moving the shade with touch input. */
fun setLockscreenShadeTracking(lockscreenShadeTracking: Boolean)
+ /** Sets whether the user is moving the shade with touch input. */
+ fun setTracking(tracking: Boolean)
+
/** Sets shade expansion to a value between 0-1. */
fun setShadeExpansion(shadeExpansion: Float)
/** Sets QS expansion to a value between 0-1. */
fun setQsExpansion(qsExpansion: Float)
+
+ /** Sets the shade to half collapsed with no touch input. */
+ fun programmaticCollapseShade()
}
/** Sets up shade state for tests when the scene container flag is disabled. */
@@ -104,6 +122,10 @@ class ShadeTestUtilLegacyImpl(val testScope: TestScope, val shadeRepository: Fak
shadeRepository.setLegacyLockscreenShadeTracking(lockscreenShadeTracking)
}
+ override fun setTracking(tracking: Boolean) {
+ shadeRepository.setLegacyShadeTracking(tracking)
+ }
+
override fun assertFlagValid() {
Assert.assertFalse(SceneContainerFlag.isEnabled)
}
@@ -119,6 +141,11 @@ class ShadeTestUtilLegacyImpl(val testScope: TestScope, val shadeRepository: Fak
shadeRepository.setQsExpansion(qsExpansion)
testScope.runCurrent()
}
+
+ override fun programmaticCollapseShade() {
+ shadeRepository.setLegacyShadeExpansion(.5f)
+ testScope.runCurrent()
+ }
}
/** Sets up shade state for tests when the scene container flag is enabled. */
@@ -127,14 +154,16 @@ class ShadeTestUtilSceneImpl(val testScope: TestScope, val sceneInteractor: Scen
val isUserInputOngoing = MutableStateFlow(true)
override fun setShadeAndQsExpansion(shadeExpansion: Float, qsExpansion: Float) {
- if (shadeExpansion == 0f) {
- setTransitionProgress(Scenes.Lockscreen, Scenes.QuickSettings, qsExpansion)
- } else if (qsExpansion == 0f) {
- setTransitionProgress(Scenes.Lockscreen, Scenes.Shade, shadeExpansion)
- } else if (shadeExpansion == 1f) {
+ if (shadeExpansion == 1f) {
setIdleScene(Scenes.Shade)
} else if (qsExpansion == 1f) {
setIdleScene(Scenes.QuickSettings)
+ } else if (shadeExpansion == 0f && qsExpansion == 0f) {
+ setIdleScene(Scenes.Lockscreen)
+ } else if (shadeExpansion == 0f) {
+ setTransitionProgress(Scenes.Lockscreen, Scenes.QuickSettings, qsExpansion)
+ } else if (qsExpansion == 0f) {
+ setTransitionProgress(Scenes.Lockscreen, Scenes.Shade, shadeExpansion)
} else {
setTransitionProgress(Scenes.Shade, Scenes.QuickSettings, qsExpansion)
}
@@ -150,6 +179,10 @@ class ShadeTestUtilSceneImpl(val testScope: TestScope, val sceneInteractor: Scen
setShadeAndQsExpansion(0f, qsExpansion)
}
+ override fun programmaticCollapseShade() {
+ setTransitionProgress(Scenes.Shade, Scenes.Lockscreen, .5f, false)
+ }
+
override fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float) {
if (lockscreenShadeExpansion == 0f) {
setIdleScene(Scenes.Lockscreen)
@@ -161,7 +194,11 @@ class ShadeTestUtilSceneImpl(val testScope: TestScope, val sceneInteractor: Scen
}
override fun setLockscreenShadeTracking(lockscreenShadeTracking: Boolean) {
- isUserInputOngoing.value = lockscreenShadeTracking
+ setTracking(lockscreenShadeTracking)
+ }
+
+ override fun setTracking(tracking: Boolean) {
+ isUserInputOngoing.value = tracking
}
private fun setIdleScene(scene: SceneKey) {
@@ -172,7 +209,12 @@ class ShadeTestUtilSceneImpl(val testScope: TestScope, val sceneInteractor: Scen
testScope.runCurrent()
}
- private fun setTransitionProgress(from: SceneKey, to: SceneKey, progress: Float) {
+ private fun setTransitionProgress(
+ from: SceneKey,
+ to: SceneKey,
+ progress: Float,
+ isInitiatedByUserInput: Boolean = true
+ ) {
sceneInteractor.changeScene(from, "test")
val transitionState =
MutableStateFlow<ObservableTransitionState>(
@@ -181,7 +223,7 @@ class ShadeTestUtilSceneImpl(val testScope: TestScope, val sceneInteractor: Scen
toScene = to,
currentScene = flowOf(to),
progress = MutableStateFlow(progress),
- isInitiatedByUserInput = true,
+ isInitiatedByUserInput = isInitiatedByUserInput,
isUserInputOngoing = isUserInputOngoing,
)
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt
index 5e71227ad49a..872eba06961e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeSceneViewModelKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui.shade.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeSceneViewModel
val Kosmos.notificationsShadeSceneViewModel: NotificationsShadeSceneViewModel by
Kosmos.Fixture {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt
new file mode 100644
index 000000000000..8c5ff1d5d216
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel
+
+val Kosmos.quickSettingsShadeSceneViewModel: QuickSettingsShadeSceneViewModel by
+ Kosmos.Fixture {
+ QuickSettingsShadeSceneViewModel(
+ applicationScope = applicationCoroutineScope,
+ overlayShadeViewModel = overlayShadeViewModel,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index 3e9ae4d2e354..1f2ecb7d172d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -37,7 +37,7 @@ import kotlinx.coroutines.yield
class FakeUserRepository @Inject constructor() : UserRepository {
companion object {
// User id to represent a non system (human) user id. We presume this is the main user.
- private const val MAIN_USER_ID = 10
+ const val MAIN_USER_ID = 10
private const val DEFAULT_SELECTED_USER = 0
private val DEFAULT_SELECTED_USER_INFO =
@@ -84,6 +84,10 @@ class FakeUserRepository @Inject constructor() : UserRepository {
override var isRefreshUsersPaused: Boolean = false
+ override suspend fun getMainUserId(): Int? {
+ return MAIN_USER_ID
+ }
+
var refreshUsersCallCount: Int = 0
private set
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index e06f40070a0a..bc608c5ac0c0 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -16,6 +16,38 @@ filegroup {
visibility: ["//visibility:public"],
}
+filegroup {
+ name: "ravenwood-services-policies",
+ srcs: [
+ "texts/ravenwood-services-policies.txt",
+ ],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "ravenwood-framework-policies",
+ srcs: [
+ "texts/ravenwood-framework-policies.txt",
+ ],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "ravenwood-standard-options",
+ srcs: [
+ "texts/ravenwood-standard-options.txt",
+ ],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "ravenwood-annotation-allowed-classes",
+ srcs: [
+ "texts/ravenwood-annotation-allowed-classes.txt",
+ ],
+ visibility: ["//visibility:public"],
+}
+
java_library {
name: "ravenwood-annotations-lib",
srcs: [":ravenwood-annotations"],
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh
index beacde282d49..cf58bd2f3717 100755
--- a/ravenwood/scripts/ravenwood-stats-collector.sh
+++ b/ravenwood/scripts/ravenwood-stats-collector.sh
@@ -24,6 +24,8 @@ apis=/tmp/ravenwood-apis-all.csv
# Where the input files are.
path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/
+timestamp="$(date --iso-8601=seconds)"
+
m() {
${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
}
@@ -39,15 +41,15 @@ dump() {
local jar=$1
local file=$2
- # Use sed to remove the header + prepend the jar filename.
- sed -e '1d' -e "s/^/$jar,/" $file
+ # Remove the header row, and prepend the columns.
+ sed -e '1d' -e "s/^/$jar,$timestamp,/" $file
}
collect_stats() {
local out="$1"
{
# Copy the header, with the first column appended.
- echo -n "Jar,"
+ echo -n "Jar,Generated Date,"
head -n 1 hoststubgen_framework-minus-apex_stats.csv
dump "framework-minus-apex" hoststubgen_framework-minus-apex_stats.csv
@@ -61,7 +63,7 @@ collect_apis() {
local out="$1"
{
# Copy the header, with the first column appended.
- echo -n "Jar,"
+ echo -n "Jar,Generated Date,"
head -n 1 hoststubgen_framework-minus-apex_apis.csv
dump "framework-minus-apex" hoststubgen_framework-minus-apex_apis.csv
diff --git a/ravenwood/texts/framework-minus-apex-ravenwood-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt
index 371c3acab144..371c3acab144 100644
--- a/ravenwood/texts/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/texts/ravenwood-framework-policies.txt
diff --git a/ravenwood/texts/services.core-ravenwood-policies.txt b/ravenwood/texts/ravenwood-services-policies.txt
index d8d563e05435..d8d563e05435 100644
--- a/ravenwood/texts/services.core-ravenwood-policies.txt
+++ b/ravenwood/texts/ravenwood-services-policies.txt
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 1ba47e40b080..82579d807eba 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -128,6 +128,16 @@ flag {
}
flag {
+ name: "manager_avoid_receiver_timeout"
+ namespace: "accessibility"
+ description: "Register receivers on background handler so they have more time to complete"
+ bug: "333890389"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "pinch_zoom_zero_min_span"
namespace: "accessibility"
description: "Whether to set min span of ScaleGestureDetector to zero."
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 8a699ef39280..42f168bb4a6b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -44,10 +44,12 @@ import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.IBrailleDisplayController;
import android.accessibilityservice.MagnificationConfig;
+import android.annotation.EnforcePermission;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
+import android.annotation.PermissionManuallyEnforced;
+import android.annotation.RequiresNoPermission;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -68,6 +70,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PermissionEnforcer;
import android.os.PowerManager;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -121,7 +124,6 @@ import java.util.Set;
* This class represents an accessibility client - either an AccessibilityService or a UiAutomation.
* It is responsible for behavior common to both types of clients.
*/
-@SuppressWarnings("MissingPermissionAnnotation")
abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub
implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter,
FingerprintGestureDispatcher.FingerprintGestureClient {
@@ -339,6 +341,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
AccessibilityTrace trace, WindowManagerInternal windowManagerInternal,
SystemActionPerformer systemActionPerfomer,
AccessibilityWindowManager a11yWindowManager) {
+ super(PermissionEnforcer.fromContext(context));
mContext = context;
mWindowManagerService = windowManagerInternal;
mId = id;
@@ -469,6 +472,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return (mEventTypes != 0 && mService != null);
}
+ @RequiresNoPermission
@Override
public void setOnKeyEventResult(boolean handled, int sequence) {
if (svcConnTracingEnabled()) {
@@ -482,6 +486,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public AccessibilityServiceInfo getServiceInfo() {
if (svcConnTracingEnabled()) {
@@ -501,6 +506,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
: AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | mEventTypes;
}
+ @RequiresNoPermission
@Override
public void setServiceInfo(AccessibilityServiceInfo info) {
if (svcConnTracingEnabled()) {
@@ -536,16 +542,19 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void setInstalledAndEnabledServices(List<AccessibilityServiceInfo> infos) {
return;
}
+ @RequiresNoPermission
@Override
public List<AccessibilityServiceInfo> getInstalledAndEnabledServices() {
return null;
}
+ @RequiresNoPermission
@Override
public void setAttributionTag(String attributionTag) {
mAttributionTag = attributionTag;
@@ -558,6 +567,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
protected abstract boolean hasRightsToCurrentUserLocked();
@Nullable
+ @RequiresNoPermission
@Override
public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
if (svcConnTracingEnabled()) {
@@ -606,6 +616,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mDisplayTypes = displayTypes;
}
+ @RequiresNoPermission
@Override
public AccessibilityWindowInfo getWindow(int windowId) {
if (svcConnTracingEnabled()) {
@@ -646,6 +657,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
long accessibilityNodeId, String viewIdResName, int interactionId,
@@ -722,6 +734,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return null;
}
+ @RequiresNoPermission
@Override
public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
long accessibilityNodeId, String text, int interactionId,
@@ -797,6 +810,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return null;
}
+ @RequiresNoPermission
@Override
public String[] findAccessibilityNodeInfoByAccessibilityId(
int accessibilityWindowId, long accessibilityNodeId, int interactionId,
@@ -875,6 +889,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return null;
}
+ @RequiresNoPermission
@Override
public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
int focusType, int interactionId,
@@ -952,6 +967,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return null;
}
+ @RequiresNoPermission
@Override
public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
int direction, int interactionId,
@@ -1028,6 +1044,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return null;
}
+ @RequiresNoPermission
@Override
public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
if (svcConnTracingEnabled()) {
@@ -1036,6 +1053,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
if (svcConnTracingEnabled()) {
@@ -1044,6 +1062,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public boolean performAccessibilityAction(int accessibilityWindowId,
long accessibilityNodeId, int action, Bundle arguments, int interactionId,
@@ -1075,6 +1094,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
action, arguments, interactionId, callback, mFetchFlags, interrogatingTid);
}
+ @RequiresNoPermission
@Override
public boolean performGlobalAction(int action) {
if (svcConnTracingEnabled()) {
@@ -1093,6 +1113,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
if (svcConnTracingEnabled()) {
@@ -1111,6 +1132,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public boolean isFingerprintGestureDetectionAvailable() {
if (svcConnTracingEnabled()) {
@@ -1133,6 +1155,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
@Nullable
+ @RequiresNoPermission
@Override
public MagnificationConfig getMagnificationConfig(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1151,6 +1174,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public float getMagnificationScale(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1169,6 +1193,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public Region getMagnificationRegion(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1193,6 +1218,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
+ @RequiresNoPermission
@Override
public Region getCurrentMagnificationRegion(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1216,6 +1242,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public float getMagnificationCenterX(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1237,6 +1264,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public float getMagnificationCenterY(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1258,6 +1286,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public boolean resetMagnification(int displayId, boolean animate) {
if (svcConnTracingEnabled()) {
@@ -1282,6 +1311,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public boolean resetCurrentMagnification(int displayId, boolean animate) {
if (svcConnTracingEnabled()) {
@@ -1307,6 +1337,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public boolean setMagnificationConfig(int displayId,
@NonNull MagnificationConfig config, boolean animate) {
@@ -1333,6 +1364,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
if (svcConnTracingEnabled()) {
@@ -1351,6 +1383,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return mInvocationHandler.isMagnificationCallbackEnabled(displayId);
}
+ @RequiresNoPermission
@Override
public void setSoftKeyboardCallbackEnabled(boolean enabled) {
if (svcConnTracingEnabled()) {
@@ -1364,6 +1397,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void takeScreenshotOfWindow(int accessibilityWindowId, int interactionId,
ScreenCapture.ScreenCaptureListener listener,
@@ -1414,6 +1448,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void takeScreenshot(int displayId, RemoteCallback callback) {
if (svcConnTracingEnabled()) {
@@ -1553,6 +1588,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
@Override
+ @PermissionManuallyEnforced
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
synchronized (mLock) {
@@ -1649,6 +1685,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
* @param displayId The id of the logical display that was added.
* @return window token.
*/
+ @RequiresNoPermission
@Override
public IBinder getOverlayWindowToken(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1670,6 +1707,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
* @param token The token
* @return window id
*/
+ @RequiresNoPermission
@Override
public int getWindowIdForLeashToken(@NonNull IBinder token) {
if (svcConnTracingEnabled()) {
@@ -2523,6 +2561,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return mSendMotionEvents;
}
+ @RequiresNoPermission
@Override
public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
if (svcConnTracingEnabled()) {
@@ -2537,6 +2576,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
if (svcConnTracingEnabled()) {
@@ -2551,6 +2591,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void setFocusAppearance(int strokeWidth, int color) {
if (svcConnTracingEnabled()) {
@@ -2558,6 +2599,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void setCacheEnabled(boolean enabled) {
if (svcConnTracingEnabled()) {
@@ -2574,6 +2616,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
int processId, long threadId, int callingUid, Bundle callingStack) {
@@ -2629,6 +2672,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mTrace.logTrace(TRACE_WM + "." + methodName, FLAGS_WINDOW_MANAGER_INTERNAL, params);
}
+ @RequiresNoPermission
@Override
public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
final long identity = Binder.clearCallingIdentity();
@@ -2647,6 +2691,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return false;
}
+ @RequiresNoPermission
@Override
public void requestTouchExploration(int displayId) {
final long identity = Binder.clearCallingIdentity();
@@ -2657,6 +2702,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void requestDragging(int displayId, int pointerId) {
final long identity = Binder.clearCallingIdentity();
@@ -2667,6 +2713,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void requestDelegating(int displayId) {
final long identity = Binder.clearCallingIdentity();
@@ -2677,6 +2724,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void onDoubleTap(int displayId) {
final long identity = Binder.clearCallingIdentity();
@@ -2687,6 +2735,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void onDoubleTapAndHold(int displayId) {
final long identity = Binder.clearCallingIdentity();
@@ -2700,6 +2749,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
/**
* Sets the scaling factor for animations.
*/
+ @RequiresNoPermission
@Override
public void setAnimationScale(float scale) {
final long identity = Binder.clearCallingIdentity();
@@ -2717,6 +2767,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void attachAccessibilityOverlayToDisplay(
int interactionId,
@@ -2733,6 +2784,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ @RequiresNoPermission
@Override
public void attachAccessibilityOverlayToWindow(
int interactionId,
@@ -2779,12 +2831,14 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
@Override
- @SuppressLint("AndroidFrameworkRequiresPermission") // Unsupported in Abstract class
+ @EnforcePermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void connectBluetoothBrailleDisplay(String bluetoothAddress,
IBrailleDisplayController controller) {
+ connectBluetoothBrailleDisplay_enforcePermission();
throw new UnsupportedOperationException();
}
+ @RequiresNoPermission
@Override
public void connectUsbBrailleDisplay(UsbDevice usbDevice,
IBrailleDisplayController controller) {
@@ -2792,8 +2846,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
@Override
- @SuppressLint("AndroidFrameworkRequiresPermission") // Unsupported in Abstract class
+ @EnforcePermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)
public void setTestBrailleDisplayData(List<Bundle> brailleDisplays) {
+ setTestBrailleDisplayData_enforcePermission();
throw new UnsupportedOperationException();
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 726a01c59a2e..c70b6419e3b8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -986,6 +986,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
+ Handler receiverHandler =
+ Flags.managerAvoidReceiverTimeout() ? BackgroundThread.getHandler() : null;
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1033,7 +1035,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
}
- }, UserHandle.ALL, intentFilter, null, null);
+ }, UserHandle.ALL, intentFilter, null, receiverHandler);
final IntentFilter filter = new IntentFilter();
filter.addAction(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 1f65e15c1bff..786d167af5de 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -30,10 +30,10 @@ import android.accessibilityservice.BrailleDisplayController;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.IBrailleDisplayController;
import android.accessibilityservice.TouchInteractionController;
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
+import android.annotation.RequiresNoPermission;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
@@ -79,7 +79,6 @@ import java.util.Set;
* passed to the service it represents as soon it is bound. It also serves as the
* connection for the service.
*/
-@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
private static final String LOG_TAG = "AccessibilityServiceConnection";
@@ -110,6 +109,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
mUserId = userId;
}
+ @RequiresNoPermission
@Override
public void sessionCreated(IAccessibilityInputMethodSession session, int id) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ASC.sessionCreated");
@@ -196,6 +196,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
return mSecurityPolicy.canRetrieveWindowContentLocked(this) && mRetrieveInteractiveWindows;
}
+ @RequiresNoPermission
@Override
public void disableSelf() {
if (svcConnTracingEnabled()) {
@@ -253,6 +254,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
}
+ @RequiresNoPermission
@Override
public AccessibilityServiceInfo getServiceInfo() {
return mAccessibilityServiceInfo;
@@ -330,6 +332,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
return false;
}
+ @RequiresNoPermission
@Override
public boolean setSoftKeyboardShowMode(int showMode) {
if (svcConnTracingEnabled()) {
@@ -351,6 +354,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
}
+ @RequiresNoPermission
@Override
public int getSoftKeyboardShowMode() {
if (svcConnTracingEnabled()) {
@@ -365,6 +369,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
}
+ @RequiresNoPermission
@Override
public boolean switchToInputMethod(String imeId) {
if (svcConnTracingEnabled()) {
@@ -386,6 +391,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
return result;
}
+ @RequiresNoPermission
@Override
@AccessibilityService.SoftKeyboardController.EnableImeResult
public int setInputMethodEnabled(String imeId, boolean enabled) throws SecurityException {
@@ -421,6 +427,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
return ENABLE_IME_FAIL_UNKNOWN;
}
+ @RequiresNoPermission
@Override
public boolean isAccessibilityButtonAvailable() {
if (svcConnTracingEnabled()) {
@@ -535,6 +542,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
}
+ @RequiresNoPermission
@Override
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
synchronized (mLock) {
@@ -569,6 +577,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
}
+ @RequiresNoPermission
@Override
public void setFocusAppearance(int strokeWidth, int color) {
AccessibilityUserState userState = mUserStateWeakReference.get();
@@ -683,16 +692,15 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
* {@link android.bluetooth.BluetoothDevice#getAddress()}.
*/
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
+ @EnforcePermission(Manifest.permission.BLUETOOTH_CONNECT)
public void connectBluetoothBrailleDisplay(
@NonNull String bluetoothAddress, @NonNull IBrailleDisplayController controller) {
+ connectBluetoothBrailleDisplay_enforcePermission();
if (!android.view.accessibility.Flags.brailleDisplayHid()) {
throw new IllegalStateException("Flag BRAILLE_DISPLAY_HID not enabled");
}
Objects.requireNonNull(bluetoothAddress);
Objects.requireNonNull(controller);
- mContext.enforceCallingPermission(Manifest.permission.BLUETOOTH_CONNECT,
- "Missing BLUETOOTH_CONNECT permission");
if (!BluetoothAdapter.checkBluetoothAddress(bluetoothAddress)) {
throw new IllegalArgumentException(
bluetoothAddress + " is not a valid Bluetooth address");
@@ -728,7 +736,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
*
* <p>The caller package must already have USB permission for this {@link UsbDevice}.
*/
- @SuppressLint("MissingPermission") // system_server has the required MANAGE_USB permission
+ @RequiresNoPermission
@Override
@NonNull
public void connectUsbBrailleDisplay(@NonNull UsbDevice usbDevice,
@@ -783,11 +791,10 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
@Override
- @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ @EnforcePermission(Manifest.permission.MANAGE_ACCESSIBILITY)
public void setTestBrailleDisplayData(List<Bundle> brailleDisplays) {
+ setTestBrailleDisplayData_enforcePermission();
// Enforce that this TestApi is only called by trusted (test) callers.
- mContext.enforceCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY,
- "Missing MANAGE_ACCESSIBILITY permission");
mTestBrailleDisplays = brailleDisplays;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index b77b2bef57a2..4cb3d247edb0 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -24,6 +24,8 @@ import android.accessibilityservice.AccessibilityTrace;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.MagnificationConfig;
import android.annotation.NonNull;
+import android.annotation.PermissionManuallyEnforced;
+import android.annotation.RequiresNoPermission;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -64,7 +66,6 @@ import java.util.Set;
*
* TODO(241429275): Initialize this when a proxy is registered.
*/
-@SuppressWarnings("MissingPermissionAnnotation")
public class ProxyAccessibilityServiceConnection extends AccessibilityServiceConnection {
private static final String LOG_TAG = "ProxyAccessibilityServiceConnection";
@@ -125,6 +126,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
*
* @param infos the list of enabled and installed services.
*/
+ @RequiresNoPermission
@Override
public void setInstalledAndEnabledServices(@NonNull List<AccessibilityServiceInfo> infos) {
final long identity = Binder.clearCallingIdentity();
@@ -215,6 +217,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
}
+ @RequiresNoPermission
@Override
@NonNull
public List<AccessibilityServiceInfo> getInstalledAndEnabledServices() {
@@ -224,6 +227,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
}
+ @RequiresNoPermission
@Override
public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
final AccessibilityWindowInfo.WindowListSparseArray allWindows = super.getWindows();
@@ -235,6 +239,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
return displayWindows;
}
+ @RequiresNoPermission
@Override
public void setFocusAppearance(int strokeWidth, int color) {
synchronized (mLock) {
@@ -272,6 +277,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
return mFocusColor;
}
+ @RequiresNoPermission
@Override
int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) {
@@ -314,12 +320,14 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
+ @RequiresNoPermission
@Override
public boolean isCapturingFingerprintGestures() throws UnsupportedOperationException {
throw new UnsupportedOperationException("isCapturingFingerprintGestures is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
+ @RequiresNoPermission
@Override
public void onFingerprintGestureDetectionActiveChanged(boolean active)
throws UnsupportedOperationException {
@@ -328,12 +336,14 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
+ @RequiresNoPermission
@Override
public void onFingerprintGesture(int gesture) throws UnsupportedOperationException {
throw new UnsupportedOperationException("onFingerprintGesture is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
+ @RequiresNoPermission
@Override
public boolean isFingerprintGestureDetectionAvailable() throws UnsupportedOperationException {
throw new UnsupportedOperationException("isFingerprintGestureDetectionAvailable is not"
@@ -341,6 +351,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy is not a Service */
+ @RequiresNoPermission
@Override
public void onServiceConnected(ComponentName name, IBinder service)
throws UnsupportedOperationException {
@@ -349,6 +360,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy is not a Service */
+ @RequiresNoPermission
@Override
public void onServiceDisconnected(ComponentName name)
throws UnsupportedOperationException {
@@ -357,6 +369,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
/** @throws UnsupportedOperationException since a proxy should use
* setInstalledAndEnabledServices*/
+ @RequiresNoPermission
@Override
public void setServiceInfo(AccessibilityServiceInfo info)
throws UnsupportedOperationException {
@@ -365,6 +378,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy should use A11yManager#unregister */
+ @RequiresNoPermission
@Override
public void disableSelf() throws UnsupportedOperationException {
// A proxy uses A11yManager#unregister to turn itself off.
@@ -372,12 +386,14 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not have global system access */
+ @RequiresNoPermission
@Override
public boolean performGlobalAction(int action) throws UnsupportedOperationException {
throw new UnsupportedOperationException("performGlobalAction is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need key events */
+ @RequiresNoPermission
@Override
public void setOnKeyEventResult(boolean handled, int sequence)
throws UnsupportedOperationException {
@@ -385,6 +401,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not have global system access */
+ @RequiresNoPermission
@Override
public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions()
throws UnsupportedOperationException {
@@ -393,6 +410,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
/** @throws UnsupportedOperationException since a proxy does not need magnification */
@Nullable
+ @RequiresNoPermission
@Override
public MagnificationConfig getMagnificationConfig(int displayId)
throws UnsupportedOperationException {
@@ -400,30 +418,35 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public float getMagnificationScale(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("getMagnificationScale is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public float getMagnificationCenterX(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("getMagnificationCenterX is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public float getMagnificationCenterY(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("getMagnificationCenterY is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public Region getMagnificationRegion(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("getMagnificationRegion is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public Region getCurrentMagnificationRegion(int displayId)
throws UnsupportedOperationException {
@@ -431,6 +454,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public boolean resetMagnification(int displayId, boolean animate)
throws UnsupportedOperationException {
@@ -438,6 +462,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public boolean resetCurrentMagnification(int displayId, boolean animate)
throws UnsupportedOperationException {
@@ -445,6 +470,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public boolean setMagnificationConfig(int displayId,
@androidx.annotation.NonNull MagnificationConfig config, boolean animate)
@@ -453,6 +479,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public void setMagnificationCallbackEnabled(int displayId, boolean enabled)
throws UnsupportedOperationException {
@@ -460,24 +487,28 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need magnification */
+ @RequiresNoPermission
@Override
public boolean isMagnificationCallbackEnabled(int displayId) {
throw new UnsupportedOperationException("isMagnificationCallbackEnabled is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need IME access*/
+ @RequiresNoPermission
@Override
public boolean setSoftKeyboardShowMode(int showMode) throws UnsupportedOperationException {
throw new UnsupportedOperationException("setSoftKeyboardShowMode is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need IME access */
+ @RequiresNoPermission
@Override
public int getSoftKeyboardShowMode() throws UnsupportedOperationException {
throw new UnsupportedOperationException("getSoftKeyboardShowMode is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need IME access */
+ @RequiresNoPermission
@Override
public void setSoftKeyboardCallbackEnabled(boolean enabled)
throws UnsupportedOperationException {
@@ -485,12 +516,14 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need IME access */
+ @RequiresNoPermission
@Override
public boolean switchToInputMethod(String imeId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("switchToInputMethod is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need IME access */
+ @RequiresNoPermission
@Override
public int setInputMethodEnabled(String imeId, boolean enabled)
throws UnsupportedOperationException {
@@ -498,12 +531,14 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need access to the shortcut */
+ @RequiresNoPermission
@Override
public boolean isAccessibilityButtonAvailable() throws UnsupportedOperationException {
throw new UnsupportedOperationException("isAccessibilityButtonAvailable is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
+ @RequiresNoPermission
@Override
public void sendGesture(int sequence, ParceledListSlice gestureSteps)
throws UnsupportedOperationException {
@@ -511,6 +546,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
+ @RequiresNoPermission
@Override
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)
throws UnsupportedOperationException {
@@ -518,6 +554,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need access to screenshots */
+ @RequiresNoPermission
@Override
public void takeScreenshot(int displayId, RemoteCallback callback)
throws UnsupportedOperationException {
@@ -525,6 +562,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
+ @RequiresNoPermission
@Override
public void setGestureDetectionPassthroughRegion(int displayId, Region region)
throws UnsupportedOperationException {
@@ -533,6 +571,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
+ @RequiresNoPermission
@Override
public void setTouchExplorationPassthroughRegion(int displayId, Region region)
throws UnsupportedOperationException {
@@ -541,6 +580,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
+ @RequiresNoPermission
@Override
public void setServiceDetectsGesturesEnabled(int displayId, boolean mode)
throws UnsupportedOperationException {
@@ -549,36 +589,42 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
}
/** @throws UnsupportedOperationException since a proxy does not need touch input access */
+ @RequiresNoPermission
@Override
public void requestTouchExploration(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("requestTouchExploration is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need touch input access */
+ @RequiresNoPermission
@Override
public void requestDragging(int displayId, int pointerId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("requestDragging is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need touch input access */
+ @RequiresNoPermission
@Override
public void requestDelegating(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("requestDelegating is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need touch input access */
+ @RequiresNoPermission
@Override
public void onDoubleTap(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("onDoubleTap is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need touch input access */
+ @RequiresNoPermission
@Override
public void onDoubleTapAndHold(int displayId) throws UnsupportedOperationException {
throw new UnsupportedOperationException("onDoubleTapAndHold is not supported");
}
/** @throws UnsupportedOperationException since a proxy does not need touch input access */
+ @RequiresNoPermission
@Override
public void setAnimationScale(float scale) throws UnsupportedOperationException {
throw new UnsupportedOperationException("setAnimationScale is not supported");
@@ -615,6 +661,7 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
return updated;
}
+ @PermissionManuallyEnforced
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index aad9e24ee8cc..63a183d506f8 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -21,6 +21,8 @@ import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityTrace;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.annotation.Nullable;
+import android.annotation.PermissionManuallyEnforced;
+import android.annotation.RequiresNoPermission;
import android.app.UiAutomation;
import android.content.ComponentName;
import android.content.Context;
@@ -242,7 +244,6 @@ class UiAutomationManager {
}
}
- @SuppressWarnings("MissingPermissionAnnotation")
private class UiAutomationService extends AbstractAccessibilityServiceConnection {
private final Handler mMainHandler;
@@ -318,6 +319,7 @@ class UiAutomationManager {
return true;
}
+ @PermissionManuallyEnforced
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -330,31 +332,37 @@ class UiAutomationManager {
}
// Since this isn't really an accessibility service, several methods are just stubbed here.
+ @RequiresNoPermission
@Override
public boolean setSoftKeyboardShowMode(int mode) {
return false;
}
+ @RequiresNoPermission
@Override
public int getSoftKeyboardShowMode() {
return 0;
}
+ @RequiresNoPermission
@Override
public boolean switchToInputMethod(String imeId) {
return false;
}
+ @RequiresNoPermission
@Override
public int setInputMethodEnabled(String imeId, boolean enabled) {
return AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_UNKNOWN;
}
+ @RequiresNoPermission
@Override
public boolean isAccessibilityButtonAvailable() {
return false;
}
+ @RequiresNoPermission
@Override
public void disableSelf() {}
@@ -375,6 +383,7 @@ class UiAutomationManager {
@Override
public void onFingerprintGesture(int gesture) {}
+ @RequiresNoPermission
@Override
public void takeScreenshot(int displayId, RemoteCallback callback) {}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 970129231f03..763879e5379a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -1625,13 +1625,13 @@ public final class AutofillManagerService
final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
@Override
public void addClient(IAutoFillManagerClient client, ComponentName componentName,
- int userId, IResultReceiver receiver) {
+ int userId, IResultReceiver receiver, boolean credmanRequested) {
int flags = 0;
try {
synchronized (mLock) {
final int enabledFlags =
getServiceForUserWithLocalBinderIdentityLocked(userId)
- .addClientLocked(client, componentName);
+ .addClientLocked(client, componentName, credmanRequested);
if (enabledFlags != 0) {
flags |= enabledFlags;
}
@@ -1644,7 +1644,7 @@ public final class AutofillManagerService
}
} catch (Exception ex) {
// Don't do anything, send back default flags
- Log.wtf(TAG, "addClient(): failed " + ex.toString());
+ Log.wtf(TAG, "addClient(): failed " + ex.toString(), ex);
} finally {
send(receiver, flags);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 68222298b94c..92acce24e64e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -33,6 +33,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -96,6 +97,7 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.Random;
/**
* Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
@@ -293,19 +295,31 @@ final class AutofillManagerServiceImpl
* @return {@code 0} if disabled, {@code FLAG_ADD_CLIENT_ENABLED} if enabled (it might be
* OR'ed with {@code FLAG_AUGMENTED_AUTOFILL_REQUEST}).
*/
- @GuardedBy("mLock")
- int addClientLocked(IAutoFillManagerClient client, ComponentName componentName) {
- if (mClients == null) {
- mClients = new RemoteCallbackList<>();
- }
- mClients.register(client);
+ int addClientLocked(IAutoFillManagerClient client, ComponentName componentName,
+ boolean credmanRequested) {
+ synchronized (mLock) {
+ ComponentName credComponentName = getCredentialAutofillService(getContext());
+
+ if (!credmanRequested
+ && Objects.equals(credComponentName,
+ mInfo == null ? null : mInfo.getServiceInfo().getComponentName())) {
+ // If the service component name corresponds to cred component name, then it means
+ // no autofill provider is selected by the user. Cred Autofill Service should only
+ // be active if there is a credman request.
+ return 0;
+ }
+ if (mClients == null) {
+ mClients = new RemoteCallbackList<>();
+ }
+ mClients.register(client);
- if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;
+ if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;
- // Check if it's enabled for augmented autofill
- if (componentName != null && isAugmentedAutofillServiceAvailableLocked()
- && isWhitelistedForAugmentedAutofillLocked(componentName)) {
- return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
+ // Check if it's enabled for augmented autofill
+ if (componentName != null && isAugmentedAutofillServiceAvailableLocked()
+ && isWhitelistedForAugmentedAutofillLocked(componentName)) {
+ return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
+ }
}
// No flags / disabled
@@ -1486,6 +1500,22 @@ final class AutofillManagerServiceImpl
return true;
}
+ @Nullable
+ private ComponentName getCredentialAutofillService(Context context) {
+ ComponentName componentName = null;
+ String credentialManagerAutofillCompName = context.getResources().getString(
+ R.string.config_defaultCredentialManagerAutofillService);
+ if (credentialManagerAutofillCompName != null
+ && !credentialManagerAutofillCompName.isEmpty()) {
+ componentName = ComponentName.unflattenFromString(
+ credentialManagerAutofillCompName);
+ }
+ if (componentName == null) {
+ Slog.w(TAG, "Invalid CredentialAutofillService");
+ }
+ return componentName;
+ }
+
@GuardedBy("mLock")
private int getAugmentedAutofillServiceUidLocked() {
if (mRemoteAugmentedAutofillServiceInfo == null) {
diff --git a/services/autofill/java/com/android/server/autofill/SaveEventLogger.java b/services/autofill/java/com/android/server/autofill/SaveEventLogger.java
index 4f95893442a5..b7f12adc90d4 100644
--- a/services/autofill/java/com/android/server/autofill/SaveEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/SaveEventLogger.java
@@ -117,7 +117,7 @@ public class SaveEventLogger {
private final int mSessionId;
private Optional<SaveEventInternal> mEventInternal;
- private long mSessionStartTimestamp;
+ private final long mSessionStartTimestamp;
private SaveEventLogger(int sessionId, long sessionStartTimestamp) {
mSessionId = sessionId;
@@ -227,13 +227,11 @@ public class SaveEventLogger {
});
}
- /* Returns timestamp (relative to mSessionStartTimestamp) or UNINITIATED_TIMESTAMP if mSessionStartTimestamp is not set */
- private long getCurrentTimestamp() {
- long timestamp = UNINITIATED_TIMESTAMP;
- if (mSessionStartTimestamp != UNINITIATED_TIMESTAMP) {
- timestamp = SystemClock.elapsedRealtime() - mSessionStartTimestamp;
- }
- return timestamp;
+ /**
+ * Returns timestamp (relative to mSessionStartTimestamp)
+ */
+ private long getElapsedTime() {
+ return SystemClock.elapsedRealtime() - mSessionStartTimestamp;
}
/**
@@ -247,7 +245,7 @@ public class SaveEventLogger {
/** Set latency_save_ui_display_millis as long as mEventInternal presents. */
public void maybeSetLatencySaveUiDisplayMillis() {
- maybeSetLatencySaveUiDisplayMillis(getCurrentTimestamp());
+ maybeSetLatencySaveUiDisplayMillis(getElapsedTime());
}
/**
@@ -261,7 +259,7 @@ public class SaveEventLogger {
/** Set latency_save_request_millis as long as mEventInternal presents. */
public void maybeSetLatencySaveRequestMillis() {
- maybeSetLatencySaveRequestMillis(getCurrentTimestamp());
+ maybeSetLatencySaveRequestMillis(getElapsedTime());
}
/**
@@ -275,7 +273,7 @@ public class SaveEventLogger {
/** Set latency_save_finish_millis as long as mEventInternal presents. */
public void maybeSetLatencySaveFinishMillis() {
- maybeSetLatencySaveFinishMillis(getCurrentTimestamp());
+ maybeSetLatencySaveFinishMillis(getElapsedTime());
}
/**
@@ -288,6 +286,16 @@ public class SaveEventLogger {
}
/**
+ * Set autofill_service_uid as long as mEventInternal presents.
+ */
+ public void maybeSetAutofillServiceUid(int uid) {
+ mEventInternal.ifPresent(
+ event -> {
+ event.mServiceUid = uid;
+ });
+ }
+
+ /**
* Log an AUTOFILL_SAVE_EVENT_REPORTED event.
*/
public void logAndEndEvent() {
@@ -314,7 +322,8 @@ public class SaveEventLogger {
+ " mLatencySaveUiDisplayMillis=" + event.mLatencySaveUiDisplayMillis
+ " mLatencySaveRequestMillis=" + event.mLatencySaveRequestMillis
+ " mLatencySaveFinishMillis=" + event.mLatencySaveFinishMillis
- + " mIsFrameworkCreatedSaveInfo=" + event.mIsFrameworkCreatedSaveInfo);
+ + " mIsFrameworkCreatedSaveInfo=" + event.mIsFrameworkCreatedSaveInfo
+ + " mServiceUid=" + event.mServiceUid);
}
FrameworkStatsLog.write(
AUTOFILL_SAVE_EVENT_REPORTED,
@@ -333,7 +342,8 @@ public class SaveEventLogger {
event.mLatencySaveUiDisplayMillis,
event.mLatencySaveRequestMillis,
event.mLatencySaveFinishMillis,
- event.mIsFrameworkCreatedSaveInfo);
+ event.mIsFrameworkCreatedSaveInfo,
+ event.mServiceUid);
mEventInternal = Optional.empty();
}
@@ -349,11 +359,11 @@ public class SaveEventLogger {
boolean mCancelButtonClicked = false;
boolean mDialogDismissed = false;
boolean mIsSaved = false;
- long mLatencySaveUiDisplayMillis = 0;
- long mLatencySaveRequestMillis = 0;
- long mLatencySaveFinishMillis = 0;
+ long mLatencySaveUiDisplayMillis = UNINITIATED_TIMESTAMP;
+ long mLatencySaveRequestMillis = UNINITIATED_TIMESTAMP;
+ long mLatencySaveFinishMillis = UNINITIATED_TIMESTAMP;
boolean mIsFrameworkCreatedSaveInfo = false;
-
+ int mServiceUid = -1;
SaveEventInternal() {
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ba6b067657a3..8b13c4b762d5 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1336,8 +1336,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mPresentationStatsEventLogger.maybeSetIsCredentialRequest(isCredmanRequested);
mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
mFieldClassificationIdSnapshot);
+ mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
mFillRequestEventLogger.maybeSetRequestId(requestId);
mFillRequestEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
+ mSaveEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
+ mSessionCommittedEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
if (mSessionFlags.mInlineSupportedByService) {
mFillRequestEventLogger.maybeSetInlineSuggestionHostUid(mContext, userId);
}
@@ -1493,10 +1496,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mCredentialAutofillService = getCredentialAutofillService(context);
- ComponentName primaryServiceComponentName, secondaryServiceComponentName;
+ ComponentName primaryServiceComponentName, secondaryServiceComponentName = null;
if (isPrimaryCredential) {
primaryServiceComponentName = mCredentialAutofillService;
- secondaryServiceComponentName = serviceComponentName;
+ if (serviceComponentName != null
+ && !serviceComponentName.equals(mCredentialAutofillService)) {
+ // if service component name is credential autofill service, no need to initialize
+ // secondary provider. This happens if the user sets non-autofill provider as
+ // password provider.
+ secondaryServiceComponentName = serviceComponentName;
+ }
} else {
primaryServiceComponentName = serviceComponentName;
secondaryServiceComponentName = mCredentialAutofillService;
@@ -2440,9 +2449,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mSessionFlags.mShowingSaveUi = false;
// Log onSaveRequest result.
mSaveEventLogger.maybeSetIsSaved(true);
- final long saveRequestFinishTimestamp =
- SystemClock.elapsedRealtime() - mLatencyBaseTime;
- mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp);
+ mSaveEventLogger.maybeSetLatencySaveFinishMillis();
mSaveEventLogger.logAndEndEvent();
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
@@ -2473,9 +2480,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
synchronized (mLock) {
mSessionFlags.mShowingSaveUi = false;
// Log onSaveRequest result.
- final long saveRequestFinishTimestamp =
- SystemClock.elapsedRealtime() - mLatencyBaseTime;
- mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp);
+ mSaveEventLogger.maybeSetLatencySaveFinishMillis();
mSaveEventLogger.logAndEndEvent();
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
@@ -2621,8 +2626,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
}
- final long saveRequestStartTimestamp = SystemClock.elapsedRealtime() - mLatencyBaseTime;
- mSaveEventLogger.maybeSetLatencySaveRequestMillis(saveRequestStartTimestamp);
+ mSaveEventLogger.maybeSetLatencySaveRequestMillis();
mHandler.sendMessage(obtainMessage(
AutofillManagerServiceImpl::handleSessionSave,
mService, this));
diff --git a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
index cd37073a1404..1be8548c788f 100644
--- a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
@@ -17,21 +17,15 @@
package com.android.server.autofill;
import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
+
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED;
import static com.android.server.autofill.Helper.sVerbose;
-import android.annotation.IntDef;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Slog;
import android.view.autofill.AutofillManager.AutofillCommitReason;
+
import com.android.internal.util.FrameworkStatsLog;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.Optional;
/**
@@ -91,6 +85,14 @@ public final class SessionCommittedEventLogger {
});
}
+ /** Set autofill_service_uid as long as mEventInternal presents. */
+ public void maybeSetAutofillServiceUid(int uid) {
+ mEventInternal.ifPresent(
+ event -> {
+ event.mServiceUid = uid;
+ });
+ }
+
/**
* Log an AUTOFILL_SESSION_COMMITTED event.
*/
@@ -106,7 +108,8 @@ public final class SessionCommittedEventLogger {
+ " mComponentPackageUid=" + event.mComponentPackageUid
+ " mRequestCount=" + event.mRequestCount
+ " mCommitReason=" + event.mCommitReason
- + " mSessionDurationMillis=" + event.mSessionDurationMillis);
+ + " mSessionDurationMillis=" + event.mSessionDurationMillis
+ + " mServiceUid=" + event.mServiceUid);
}
FrameworkStatsLog.write(
AUTOFILL_SESSION_COMMITTED,
@@ -114,7 +117,8 @@ public final class SessionCommittedEventLogger {
event.mComponentPackageUid,
event.mRequestCount,
event.mCommitReason,
- event.mSessionDurationMillis);
+ event.mSessionDurationMillis,
+ event.mServiceUid);
mEventInternal = Optional.empty();
}
@@ -123,6 +127,7 @@ public final class SessionCommittedEventLogger {
int mRequestCount = 0;
int mCommitReason = COMMIT_REASON_UNKNOWN;
long mSessionDurationMillis = 0;
+ int mServiceUid = -1;
SessionCommittedEventInternal() {
}
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 7acca19f9d79..e2b6bd6ae360 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -36,6 +36,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -47,6 +48,7 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.vcn.Flags;
import android.net.vcn.IVcnManagementService;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -68,6 +70,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -431,6 +434,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
mTelephonySubscriptionTracker.register();
}
+ // The system server automatically has the required permissions for #getMainUser()
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private void enforcePrimaryUser() {
final int uid = mDeps.getBinderCallingUid();
if (uid == Process.SYSTEM_UID) {
@@ -438,7 +443,20 @@ public class VcnManagementService extends IVcnManagementService.Stub {
"Calling identity was System Server. Was Binder calling identity cleared?");
}
- if (!UserHandle.getUserHandleForUid(uid).isSystem()) {
+ final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+
+ if (Flags.enforceMainUser()) {
+ final UserManager userManager = mContext.getSystemService(UserManager.class);
+
+ Binder.withCleanCallingIdentity(
+ () -> {
+ if (!Objects.equals(userManager.getMainUser(), userHandle)) {
+ throw new SecurityException(
+ "VcnManagementService can only be used by callers running as"
+ + " the main user");
+ }
+ });
+ } else if (!userHandle.isSystem()) {
throw new SecurityException(
"VcnManagementService can only be used by callers running as the primary user");
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1b3b19808dad..00c2df67c8f0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4781,7 +4781,7 @@ public class ActivityManagerService extends IActivityManager.Stub
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
bindApplicationTimeMillis = SystemClock.uptimeMillis();
- bindApplicationTimeNanos = SystemClock.elapsedRealtimeNanos();
+ bindApplicationTimeNanos = SystemClock.uptimeNanos();
mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (mPlatformCompat != null) {
@@ -4851,7 +4851,8 @@ public class ActivityManagerService extends IActivityManager.Stub
app.setBindApplicationTime(bindApplicationTimeMillis);
mProcessList.getAppStartInfoTracker()
- .reportBindApplicationTimeNanos(app, bindApplicationTimeNanos);
+ .addTimestampToStart(app, bindApplicationTimeNanos,
+ ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION);
// Make app active after binding application or client may be running requests (e.g
// starting activities) before it is ready.
@@ -14317,7 +14318,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// activity manager to announce its creation.
public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId,
@BackupDestination int backupDestination) {
- long startTimeNs = SystemClock.elapsedRealtimeNanos();
+ long startTimeNs = SystemClock.uptimeNanos();
if (DEBUG_BACKUP) {
Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode
+ " targetUserId=" + targetUserId + " callingUid = " + Binder.getCallingUid()
@@ -19416,7 +19417,6 @@ public class ActivityManagerService extends IActivityManager.Stub
// If the process is known as top app, set a hint so when the process is
// started, the top priority can be applied immediately to avoid cpu being
// preempted by other processes before attaching the process of top app.
- final long startTimeNs = SystemClock.elapsedRealtimeNanos();
HostingRecord hostingRecord =
new HostingRecord(hostingType, hostingName, isTop);
ProcessRecord rec = getProcessRecordLocked(processName, info.uid);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 5af9424a025c..3cea01464c10 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -4552,10 +4552,9 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" 1: crop_windows");
pw.println(" 2: resizeable");
pw.println(" 3: resizeable_and_pipable");
- pw.println(" resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>");
- pw.println(" Makes sure <TASK_ID> is in a stack with the specified bounds.");
- pw.println(" Forces the task to be resizeable and creates a stack if no existing stack");
- pw.println(" has the specified bounds.");
+ pw.println(" resize <TASK_ID> <LEFT> <TOP> <RIGHT> <BOTTOM>");
+ pw.println(" The task is resized only if it is in multi-window windowing");
+ pw.println(" mode or freeform windowing mode.");
pw.println(" update-appinfo <USER_ID> <PACKAGE_NAME> [<PACKAGE_NAME>...]");
pw.println(" Update the ApplicationInfo objects of the listed packages for <USER_ID>");
pw.println(" without restarting any processes.");
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 2cdf596753fc..79a85182ac09 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -294,9 +294,11 @@ public final class AppStartInfoTracker {
mInProgRecords.removeAt(index);
return;
}
- info.setStartupState(ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN);
info.setLaunchMode(launchMode);
- checkCompletenessAndCallback(info);
+ if (!android.app.Flags.appStartInfoTimestamps()) {
+ info.setStartupState(ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN);
+ checkCompletenessAndCallback(info);
+ }
}
}
@@ -424,14 +426,6 @@ public final class AppStartInfoTracker {
}
}
- void reportApplicationOnCreateTimeNanos(ProcessRecord app, long timeNs) {
- if (!mEnabled) {
- return;
- }
- addTimestampToStart(app, timeNs,
- ApplicationStartInfo.START_TIMESTAMP_APPLICATION_ONCREATE);
- }
-
/**
* Helper functions for monitoring shell command.
* > adb shell am start-info-detailed-monitoring [package-name]
@@ -466,41 +460,14 @@ public final class AppStartInfoTracker {
}
}
- /** Report a bind application timestamp to add to {@link ApplicationStartInfo}. */
- public void reportBindApplicationTimeNanos(ProcessRecord app, long timeNs) {
- addTimestampToStart(app, timeNs,
- ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION);
- }
-
- void reportFirstFrameTimeNanos(ProcessRecord app, long timeNs) {
- if (!mEnabled) {
- return;
- }
- addTimestampToStart(app, timeNs,
- ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME);
- }
-
- void reportFullyDrawnTimeNanos(ProcessRecord app, long timeNs) {
- if (!mEnabled) {
- return;
- }
- addTimestampToStart(app, timeNs,
- ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN);
+ void addTimestampToStart(ProcessRecord app, long timeNs, int key) {
+ addTimestampToStart(app.info.packageName, app.uid, timeNs, key);
}
- void reportFullyDrawnTimeNanos(String processName, int uid, long timeNs) {
+ void addTimestampToStart(String packageName, int uid, long timeNs, int key) {
if (!mEnabled) {
return;
}
- addTimestampToStart(processName, uid, timeNs,
- ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN);
- }
-
- private void addTimestampToStart(ProcessRecord app, long timeNs, int key) {
- addTimestampToStart(app.info.packageName, app.uid, timeNs, key);
- }
-
- void addTimestampToStart(String packageName, int uid, long timeNs, int key) {
synchronized (mLock) {
AppStartInfoContainer container = mData.get(packageName, uid);
if (container == null) {
@@ -539,9 +506,9 @@ public final class AppStartInfoTracker {
}
/**
- * Called whenever data is added to a {@link ApplicationStartInfo} object. Checks for
- * completeness and triggers callback if a callback has been registered and the object
- * is complete.
+ * Called whenever a potentially final piece of data is added to a {@link ApplicationStartInfo}
+ * object. Checks for completeness and triggers callback if a callback has been registered and
+ * the object is complete.
*/
private void checkCompletenessAndCallback(ApplicationStartInfo startInfo) {
synchronized (mLock) {
@@ -1124,10 +1091,23 @@ public final class AppStartInfoTracker {
Long.compare(getStartTimestamp(b), getStartTimestamp(a)));
}
+ /**
+ * Add the provided key/timestamp to the most recent start record, if it is currently
+ * accepting new timestamps.
+ *
+ * Will also update the start records startup state and trigger the completion listener when
+ * appropriate.
+ */
@GuardedBy("mLock")
void addTimestampToStartLocked(int key, long timestampNs) {
+ if (mInfos.isEmpty()) {
+ if (DEBUG) Slog.d(TAG, "No records to add to.");
+ return;
+ }
+
// Records are sorted newest to oldest, grab record at index 0.
- int startupState = mInfos.get(0).getStartupState();
+ ApplicationStartInfo startInfo = mInfos.get(0);
+ int startupState = startInfo.getStartupState();
// If startup state is error then don't accept any further timestamps.
if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) {
@@ -1145,7 +1125,13 @@ public final class AppStartInfoTracker {
return;
}
- mInfos.get(0).addStartupTimestamp(key, timestampNs);
+ startInfo.addStartupTimestamp(key, timestampNs);
+
+ if (key == ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME
+ && android.app.Flags.appStartInfoTimestamps()) {
+ startInfo.setStartupState(ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN);
+ checkCompletenessAndCallback(startInfo);
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 4425a388e9e1..1379c9b5cb68 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -1021,6 +1021,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
final boolean allowWhileBooting = (r.intent.getFlags()
& Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0;
+ long startTimeNs = SystemClock.uptimeNanos();
if (DEBUG_BROADCAST) logv("Scheduling " + r + " to cold " + queue);
queue.app = mService.startProcessLocked(queue.processName, info, true, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
@@ -1032,8 +1033,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
// TODO: b/335420031 - cache receiver intent to avoid multiple calls to getReceiverIntent.
mService.mProcessList.getAppStartInfoTracker().handleProcessBroadcastStart(
- SystemClock.elapsedRealtimeNanos(), queue.app, r.getReceiverIntent(receiver),
- r.alarm /* isAlarm */);
+ startTimeNs, queue.app, r.getReceiverIntent(receiver), r.alarm /* isAlarm */);
return false;
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 28fd1977539c..a8b9e43bdae4 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -179,7 +179,7 @@ public class ContentProviderHelper {
final int expectedUserId = userId;
synchronized (mService) {
long startTime = SystemClock.uptimeMillis();
- long startElapsedTimeNs = SystemClock.elapsedRealtimeNanos();
+ long startTimeNs = SystemClock.uptimeNanos();
ProcessRecord r = null;
if (caller != null) {
@@ -587,7 +587,7 @@ public class ContentProviderHelper {
firstLaunch,
0L /* TODO: stoppedDuration */);
mService.mProcessList.getAppStartInfoTracker()
- .handleProcessContentProviderStart(startElapsedTimeNs, proc);
+ .handleProcessContentProviderStart(startTimeNs, proc);
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index a289dd16170d..cc6ae5ca03e3 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2610,6 +2610,15 @@ public class OomAdjuster {
}
}
+ // Sandbox should be able to control audio only when bound client
+ // has this capability.
+ if ((cstate.getCurCapability()
+ & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0) {
+ if (app.isSdkSandbox) {
+ capability |= PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
+ }
+ }
+
if (couldRecurse && shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
return false;
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 9b83ede09da4..95206212c99d 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -128,6 +128,7 @@ public class SettingsToPropertiesMapper {
"aoc",
"app_widgets",
"arc_next",
+ "art_mainline",
"avic",
"biometrics",
"biometrics_framework",
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 798aaee58a8e..63086525711a 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1102,6 +1102,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (onModeChangedListeners == null) {
continue;
}
+ onModeChangedListeners = new ArraySet<>(onModeChangedListeners);
}
for (int i = 0; i < changedUids.length; i++) {
final int changedUid = changedUids[i];
@@ -6396,12 +6397,13 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private void notifyWatchersOnDefaultDevice(int code, int uid) {
- final ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
+ ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
synchronized (this) {
modeChangedListenerSet = mOpModeWatchers.get(code);
if (modeChangedListenerSet == null) {
return;
}
+ modeChangedListenerSet = new ArraySet<>(modeChangedListenerSet);
}
notifyOpChanged(modeChangedListenerSet, code, uid, null, PERSISTENT_DEVICE_ID_DEFAULT);
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java b/services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java
new file mode 100644
index 000000000000..3e8acee26e81
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.biometrics;
+
+import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+
+/**
+ * Receives broadcast to biometrics dangling notification.
+ */
+public class BiometricDanglingReceiver extends BroadcastReceiver {
+ private static final String TAG = "BiometricDanglingReceiver";
+
+ public static final String ACTION_FINGERPRINT_RE_ENROLL_LAUNCH =
+ "action_fingerprint_re_enroll_launch";
+ public static final String ACTION_FINGERPRINT_RE_ENROLL_DISMISS =
+ "action_fingerprint_re_enroll_dismiss";
+
+ public static final String ACTION_FACE_RE_ENROLL_LAUNCH =
+ "action_face_re_enroll_launch";
+ public static final String ACTION_FACE_RE_ENROLL_DISMISS =
+ "action_face_re_enroll_dismiss";
+
+ public static final String FACE_SETTINGS_ACTION = "android.settings.FACE_SETTINGS";
+
+ private static final String SETTINGS_PACKAGE = "com.android.settings";
+
+ /**
+ * Constructor for BiometricDanglingReceiver.
+ *
+ * @param context context
+ * @param modality the value from BiometricsProtoEnums.MODALITY_*
+ */
+ public BiometricDanglingReceiver(@NonNull Context context, int modality) {
+ final IntentFilter intentFilter = new IntentFilter();
+ if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT) {
+ intentFilter.addAction(ACTION_FINGERPRINT_RE_ENROLL_LAUNCH);
+ intentFilter.addAction(ACTION_FINGERPRINT_RE_ENROLL_DISMISS);
+ } else if (modality == BiometricsProtoEnums.MODALITY_FACE) {
+ intentFilter.addAction(ACTION_FACE_RE_ENROLL_LAUNCH);
+ intentFilter.addAction(ACTION_FACE_RE_ENROLL_DISMISS);
+ }
+ context.registerReceiver(this, intentFilter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.d(TAG, "Received: " + intent.getAction());
+ if (ACTION_FINGERPRINT_RE_ENROLL_LAUNCH.equals(intent.getAction())) {
+ launchBiometricEnrollActivity(context, Settings.ACTION_FINGERPRINT_ENROLL);
+ BiometricNotificationUtils.cancelFingerprintReEnrollNotification(context);
+ } else if (ACTION_FINGERPRINT_RE_ENROLL_DISMISS.equals(intent.getAction())) {
+ BiometricNotificationUtils.cancelFingerprintReEnrollNotification(context);
+ } else if (ACTION_FACE_RE_ENROLL_LAUNCH.equals(intent.getAction())) {
+ launchBiometricEnrollActivity(context, FACE_SETTINGS_ACTION);
+ BiometricNotificationUtils.cancelFaceReEnrollNotification(context);
+ } else if (ACTION_FACE_RE_ENROLL_DISMISS.equals(intent.getAction())) {
+ BiometricNotificationUtils.cancelFaceReEnrollNotification(context);
+ }
+ context.unregisterReceiver(this);
+ }
+
+ private void launchBiometricEnrollActivity(Context context, String action) {
+ context.sendBroadcast(new Intent(ACTION_CLOSE_SYSTEM_DIALOGS));
+ final Intent intent = new Intent(action);
+ intent.setPackage(SETTINGS_PACKAGE);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index 0e22f7511af9..eaa5e2a6befb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -24,13 +24,18 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.face.FaceEnrollOptions;
import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.text.BidiFormatter;
import android.util.Slog;
import com.android.internal.R;
+import com.android.server.biometrics.BiometricDanglingReceiver;
+
+import java.util.List;
/**
* Biometric notification helper class.
@@ -39,6 +44,7 @@ public class BiometricNotificationUtils {
private static final String TAG = "BiometricNotificationUtils";
private static final String FACE_RE_ENROLL_NOTIFICATION_TAG = "FaceReEnroll";
+ private static final String FINGERPRINT_RE_ENROLL_NOTIFICATION_TAG = "FingerprintReEnroll";
private static final String BAD_CALIBRATION_NOTIFICATION_TAG = "FingerprintBadCalibration";
private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock";
private static final String FACE_SETTINGS_ACTION = "android.settings.FACE_SETTINGS";
@@ -50,6 +56,8 @@ public class BiometricNotificationUtils {
private static final String FACE_ENROLL_CHANNEL = "FaceEnrollNotificationChannel";
private static final String FACE_RE_ENROLL_CHANNEL = "FaceReEnrollNotificationChannel";
private static final String FINGERPRINT_ENROLL_CHANNEL = "FingerprintEnrollNotificationChannel";
+ private static final String FINGERPRINT_RE_ENROLL_CHANNEL =
+ "FingerprintReEnrollNotificationChannel";
private static final String FINGERPRINT_BAD_CALIBRATION_CHANNEL =
"FingerprintBadCalibrationNotificationChannel";
private static final long NOTIFICATION_INTERVAL_MS = 24 * 60 * 60 * 1000;
@@ -177,10 +185,124 @@ public class BiometricNotificationUtils {
BAD_CALIBRATION_NOTIFICATION_TAG, Notification.VISIBILITY_SECRET, false);
}
+ /**
+ * Shows a biometric re-enroll notification.
+ */
+ public static void showBiometricReEnrollNotification(@NonNull Context context,
+ @NonNull List<String> identifiers, boolean allIdentifiersDeleted, int modality) {
+ final boolean isFingerprint = modality == BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ final String reEnrollName = isFingerprint ? FINGERPRINT_RE_ENROLL_NOTIFICATION_TAG
+ : FACE_RE_ENROLL_NOTIFICATION_TAG;
+ if (identifiers.isEmpty()) {
+ Slog.v(TAG, "Skipping " + reEnrollName + " notification : empty list");
+ return;
+ }
+ Slog.d(TAG, "Showing " + reEnrollName + " notification :[" + identifiers.size()
+ + " identifier(s) deleted, allIdentifiersDeleted=" + allIdentifiersDeleted + "]");
+
+ final String name =
+ context.getString(R.string.device_unlock_notification_name);
+ final String title = context.getString(isFingerprint
+ ? R.string.fingerprint_dangling_notification_title
+ : R.string.face_dangling_notification_title);
+ final String content = isFingerprint
+ ? getFingerprintDanglingContentString(context, identifiers, allIdentifiersDeleted)
+ : context.getString(R.string.face_dangling_notification_msg);
+
+ // Create "Set up" notification action button.
+ final Intent setupIntent = new Intent(
+ isFingerprint ? BiometricDanglingReceiver.ACTION_FINGERPRINT_RE_ENROLL_LAUNCH
+ : BiometricDanglingReceiver.ACTION_FACE_RE_ENROLL_LAUNCH);
+ final PendingIntent setupPendingIntent = PendingIntent.getBroadcastAsUser(context, 0,
+ setupIntent, PendingIntent.FLAG_IMMUTABLE, UserHandle.CURRENT);
+ final String setupText =
+ context.getString(R.string.biometric_dangling_notification_action_set_up);
+ final Notification.Action setupAction = new Notification.Action.Builder(
+ null, setupText, setupPendingIntent).build();
+
+ // Create "Not now" notification action button.
+ final Intent notNowIntent = new Intent(
+ isFingerprint ? BiometricDanglingReceiver.ACTION_FINGERPRINT_RE_ENROLL_DISMISS
+ : BiometricDanglingReceiver.ACTION_FACE_RE_ENROLL_DISMISS);
+ final PendingIntent notNowPendingIntent = PendingIntent.getBroadcastAsUser(context, 0,
+ notNowIntent, PendingIntent.FLAG_IMMUTABLE, UserHandle.CURRENT);
+ final String notNowText = context.getString(
+ R.string.biometric_dangling_notification_action_not_now);
+ final Notification.Action notNowAction = new Notification.Action.Builder(
+ null, notNowText, notNowPendingIntent).build();
+
+ final String channel = isFingerprint ? FINGERPRINT_RE_ENROLL_CHANNEL
+ : FACE_RE_ENROLL_CHANNEL;
+ final String tag = isFingerprint ? FINGERPRINT_RE_ENROLL_NOTIFICATION_TAG
+ : FACE_RE_ENROLL_NOTIFICATION_TAG;
+
+ showNotificationHelper(context, name, title, content, setupPendingIntent, setupAction,
+ notNowAction, Notification.CATEGORY_SYSTEM, channel, tag,
+ Notification.VISIBILITY_SECRET, false);
+ }
+
+ private static String getFingerprintDanglingContentString(Context context,
+ @NonNull List<String> fingerprints, boolean allFingerprintDeleted) {
+ if (fingerprints.isEmpty()) {
+ return null;
+ }
+
+ final int resId;
+ final int size = fingerprints.size();
+ final StringBuilder first = new StringBuilder();
+ final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
+ if (size > 1) {
+ // If there are more than 1 fingerprint deleted, the "second" will be the last
+ // fingerprint and set the others to "first".
+ // For example, if we have 3 fingerprints deleted(fp1, fp2 and fp3):
+ // first = "fp1, fp2"
+ // second = "fp3"
+ final String separator = ", ";
+ String second = null;
+ for (int i = 0; i < size; i++) {
+ if (i == size - 1) {
+ second = bidiFormatter.unicodeWrap("\"" + fingerprints.get(i) + "\"");
+ } else {
+ first.append(bidiFormatter.unicodeWrap("\""));
+ first.append(bidiFormatter.unicodeWrap(fingerprints.get(i)));
+ first.append(bidiFormatter.unicodeWrap("\""));
+ if (i < size - 2) {
+ first.append(bidiFormatter.unicodeWrap(separator));
+ }
+ }
+ }
+ if (allFingerprintDeleted) {
+ resId = R.string.fingerprint_dangling_notification_msg_all_deleted_2;
+ } else {
+ resId = R.string.fingerprint_dangling_notification_msg_2;
+ }
+
+ return String.format(context.getString(resId), first, second);
+ } else {
+ if (allFingerprintDeleted) {
+ resId = R.string.fingerprint_dangling_notification_msg_all_deleted_1;
+ } else {
+ resId = R.string.fingerprint_dangling_notification_msg_1;
+ }
+ first.append(bidiFormatter.unicodeWrap("\""));
+ first.append(bidiFormatter.unicodeWrap(fingerprints.get(0)));
+ first.append(bidiFormatter.unicodeWrap("\""));
+ return String.format(context.getString(resId), first);
+ }
+ }
+
+ private static void showNotificationHelper(Context context, String name, String title,
+ String content, PendingIntent pendingIntent, String category, String channelName,
+ String notificationTag, int visibility, boolean listenToDismissEvent) {
+ showNotificationHelper(context, name, title, content, pendingIntent,
+ null /* positiveAction */, null /* negativeAction */, category, channelName,
+ notificationTag, visibility, listenToDismissEvent);
+ }
+
private static void showNotificationHelper(Context context, String name, String title,
- String content, PendingIntent pendingIntent, String category,
- String channelName, String notificationTag, int visibility,
- boolean listenToDismissEvent) {
+ String content, PendingIntent pendingIntent, Notification.Action positiveAction,
+ Notification.Action negativeAction, String category, String channelName,
+ String notificationTag, int visibility, boolean listenToDismissEvent) {
Slog.v(TAG," listenToDismissEvent = " + listenToDismissEvent);
final PendingIntent dismissIntent = PendingIntent.getActivityAsUser(context,
0 /* requestCode */, DISMISS_FRR_INTENT, PendingIntent.FLAG_IMMUTABLE /* flags */,
@@ -202,6 +324,12 @@ public class BiometricNotificationUtils {
.setContentIntent(pendingIntent)
.setVisibility(visibility);
+ if (positiveAction != null) {
+ builder.addAction(positiveAction);
+ }
+ if (negativeAction != null) {
+ builder.addAction(negativeAction);
+ }
if (listenToDismissEvent) {
builder.setDeleteIntent(dismissIntent);
}
@@ -253,4 +381,14 @@ public class BiometricNotificationUtils {
UserHandle.CURRENT);
}
+ /**
+ * Cancels a fingerprint enrollment notification
+ */
+ public static void cancelFingerprintReEnrollNotification(@NonNull Context context) {
+ final NotificationManager notificationManager =
+ context.getSystemService(NotificationManager.class);
+ notificationManager.cancelAsUser(FINGERPRINT_RE_ENROLL_NOTIFICATION_TAG, NOTIFICATION_ID,
+ UserHandle.CURRENT);
+ }
+
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
index 6daaad1baf83..81ab26dd581e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -22,6 +22,7 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.os.IBinder;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
@@ -44,6 +45,7 @@ public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T>
private List<? extends BiometricAuthenticator.Identifier> mEnrolledList;
// List of templates to remove from the HAL
private List<BiometricAuthenticator.Identifier> mUnknownHALTemplates = new ArrayList<>();
+ private final int mInitialEnrolledSize;
protected InternalEnumerateClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
@NonNull IBinder token, int userId, @NonNull String owner,
@@ -55,6 +57,7 @@ public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T>
super(context, lazyDaemon, token, null /* ClientMonitorCallbackConverter */, userId, owner,
0 /* cookie */, sensorId, logger, biometricContext);
mEnrolledList = enrolledList;
+ mInitialEnrolledSize = mEnrolledList.size();
mUtils = utils;
}
@@ -111,8 +114,10 @@ public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T>
// At this point, mEnrolledList only contains templates known to the framework and
// not the HAL.
+ final List<String> names = new ArrayList<>();
for (int i = 0; i < mEnrolledList.size(); i++) {
BiometricAuthenticator.Identifier identifier = mEnrolledList.get(i);
+ names.add(identifier.getName().toString());
Slog.e(TAG, "doTemplateCleanup(): Removing dangling template from framework: "
+ identifier.getBiometricId() + " " + identifier.getName());
mUtils.removeBiometricForUser(getContext(),
@@ -120,6 +125,11 @@ public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T>
getLogger().logUnknownEnrollmentInFramework();
}
+
+ // Send dangling notification.
+ if (!names.isEmpty()) {
+ sendDanglingNotification(names);
+ }
mEnrolledList.clear();
}
@@ -127,8 +137,24 @@ public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T>
return mUnknownHALTemplates;
}
+ /**
+ * Send the dangling notification.
+ */
+ @VisibleForTesting
+ public void sendDanglingNotification(@NonNull List<String> identifierNames) {
+ if (!identifierNames.isEmpty()) {
+ Slog.e(TAG, "sendDanglingNotification(): initial enrolledSize="
+ + mInitialEnrolledSize + ", after clean up size=" + mEnrolledList.size());
+ final boolean allIdentifiersDeleted = mEnrolledList.size() == mInitialEnrolledSize;
+ BiometricNotificationUtils.showBiometricReEnrollNotification(
+ getContext(), identifierNames, allIdentifiersDeleted, getModality());
+ }
+ }
+
@Override
public int getProtoEnum() {
return BiometricsProto.CM_ENUMERATE;
}
+
+ protected abstract int getModality();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java
index d85455e0e76b..6ce3bc59eb56 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java
@@ -18,12 +18,14 @@ package com.android.server.biometrics.sensors.face.aidl;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.IFace;
import android.hardware.face.Face;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.BiometricUtils;
@@ -35,7 +37,8 @@ import java.util.function.Supplier;
/**
* Face-specific internal enumerate client for the {@link IFace} AIDL HAL interface.
*/
-class FaceInternalEnumerateClient extends InternalEnumerateClient<AidlSession> {
+@VisibleForTesting
+public class FaceInternalEnumerateClient extends InternalEnumerateClient<AidlSession> {
private static final String TAG = "FaceInternalEnumerateClient";
FaceInternalEnumerateClient(@NonNull Context context,
@@ -56,4 +59,9 @@ class FaceInternalEnumerateClient extends InternalEnumerateClient<AidlSession> {
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ @Override
+ protected int getModality() {
+ return BiometricsProtoEnums.MODALITY_FACE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index e71cffe0b8c5..f0a418951505 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -52,6 +52,7 @@ import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver;
import com.android.server.biometrics.AuthenticationStatsCollector;
+import com.android.server.biometrics.BiometricDanglingReceiver;
import com.android.server.biometrics.BiometricHandlerProvider;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
@@ -201,6 +202,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mBiometricHandlerProvider = biometricHandlerProvider;
initAuthenticationBroadcastReceiver();
+ initFaceDanglingBroadcastReceiver();
initSensors(resetLockoutRequiresChallenge, props);
}
@@ -214,6 +216,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
});
}
+ private void initFaceDanglingBroadcastReceiver() {
+ new BiometricDanglingReceiver(mContext, BiometricsProtoEnums.MODALITY_FACE);
+ }
+
private void initSensors(boolean resetLockoutRequiresChallenge, SensorProps[] props) {
if (resetLockoutRequiresChallenge) {
Slog.d(getTag(), "Adding HIDL configs");
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClient.java
index a5a832aaaf59..2849bd9c92a3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClient.java
@@ -18,11 +18,13 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.fingerprint.Fingerprint;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.BiometricUtils;
@@ -35,7 +37,8 @@ import java.util.function.Supplier;
* Fingerprint-specific internal client supporting the
* {@link android.hardware.biometrics.fingerprint.IFingerprint} AIDL interface.
*/
-class FingerprintInternalEnumerateClient extends InternalEnumerateClient<AidlSession> {
+@VisibleForTesting
+public class FingerprintInternalEnumerateClient extends InternalEnumerateClient<AidlSession> {
private static final String TAG = "FingerprintInternalEnumerateClient";
protected FingerprintInternalEnumerateClient(@NonNull Context context,
@@ -56,4 +59,9 @@ class FingerprintInternalEnumerateClient extends InternalEnumerateClient<AidlSes
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ @Override
+ protected int getModality() {
+ return BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 6874c71267fb..c0dcd4943260 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -58,6 +58,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver;
import com.android.server.biometrics.AuthenticationStatsCollector;
+import com.android.server.biometrics.BiometricDanglingReceiver;
import com.android.server.biometrics.BiometricHandlerProvider;
import com.android.server.biometrics.Flags;
import com.android.server.biometrics.Utils;
@@ -205,6 +206,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricHandlerProvider = biometricHandlerProvider;
initAuthenticationBroadcastReceiver();
+ initFingerprintDanglingBroadcastReceiver();
initSensors(resetLockoutRequiresHardwareAuthToken, props, gestureAvailabilityDispatcher);
}
@@ -218,6 +220,10 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
});
}
+ private void initFingerprintDanglingBroadcastReceiver() {
+ new BiometricDanglingReceiver(mContext, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ }
+
private void initSensors(boolean resetLockoutRequiresHardwareAuthToken, SensorProps[] props,
GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
if (!resetLockoutRequiresHardwareAuthToken) {
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index a46975fb3567..11ef5776a47a 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -285,7 +285,8 @@ public class BrightnessClamperController {
List<BrightnessStateModifier> modifiers = new ArrayList<>();
modifiers.add(new DisplayDimModifier(context));
modifiers.add(new BrightnessLowPowerModeModifier());
- if (flags.isEvenDimmerEnabled() && displayDeviceConfig != null) {
+ if (flags.isEvenDimmerEnabled() && displayDeviceConfig != null
+ && displayDeviceConfig.isEvenDimmerAvailable()) {
modifiers.add(new BrightnessLowLuxModifier(handler, listener, context,
displayDeviceConfig));
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
index a3dfe229eb59..7ba4a4d9c4dd 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
@@ -87,9 +87,7 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
mContentResolver, Settings.Secure.EVEN_DIMMER_MIN_NITS,
/* def= */ MIN_NITS_DEFAULT, userId);
- boolean isActive = Settings.Secure.getFloatForUser(mContentResolver,
- Settings.Secure.EVEN_DIMMER_ACTIVATED,
- /* def= */ 0, userId) == 1.0f && mAutoBrightnessEnabled;
+ boolean isActive = isSettingEnabled() && mAutoBrightnessEnabled;
float luxBasedNitsLowerBound = mDisplayDeviceConfig.getMinNitsFromLux(mAmbientLux);
@@ -202,6 +200,17 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
pw.println(" mMinNitsAllowed=" + mMinNitsAllowed);
}
+ /**
+ * Defaults to true, on devices where setting is unset.
+ *
+ * @return if setting indicates feature is enabled
+ */
+ private boolean isSettingEnabled() {
+ return Settings.Secure.getFloatForUser(mContentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED,
+ /* def= */ 1.0f, UserHandle.USER_CURRENT) == 1.0f;
+ }
+
private float getBrightnessFromNits(float nits) {
return mDisplayDeviceConfig.getBrightnessFromBacklight(
mDisplayDeviceConfig.getBacklightFromNits(nits));
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 61514abec102..d2d0279e768e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -304,6 +304,10 @@ public class HdmiControlService extends SystemService {
// Make sure HdmiCecConfig is instantiated and the XMLs are read.
private HdmiCecConfig mHdmiCecConfig;
+ // Timeout value for start ARC action after an established eARC connection was terminated,
+ // e.g. because eARC was disabled in Settings.
+ private static final int EARC_TRIGGER_START_ARC_ACTION_DELAY = 500;
+
/**
* Interface to report send result.
*/
@@ -5041,7 +5045,12 @@ public class HdmiControlService extends SystemService {
// AudioService here that the eARC connection is terminated.
HdmiLogger.debug("eARC state change [new: HDMI_EARC_STATUS_ARC_PENDING(2)]");
notifyEarcStatusToAudioService(false, new ArrayList<>());
- startArcAction(true, null);
+ mHandler.postDelayed( new Runnable() {
+ @Override
+ public void run() {
+ startArcAction(true, null);
+ }
+ }, EARC_TRIGGER_START_ARC_ACTION_DELAY);
getAtomWriter().earcStatusChanged(isEarcSupported(), isEarcEnabled(),
oldEarcStatus, status, HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED);
} else {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 14d04119c55f..0fde760fd02a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -307,14 +307,17 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@MultiUserUnawareField
private final InputMethodMenuController mMenuController;
@MultiUserUnawareField
- @NonNull private final AutofillSuggestionsController mAutofillController;
+ @NonNull
+ private final AutofillSuggestionsController mAutofillController;
@GuardedBy("ImfLock.class")
@MultiUserUnawareField
- @NonNull private final ImeVisibilityStateComputer mVisibilityStateComputer;
+ @NonNull
+ private final ImeVisibilityStateComputer mVisibilityStateComputer;
@GuardedBy("ImfLock.class")
- @NonNull private final DefaultImeVisibilityApplier mVisibilityApplier;
+ @NonNull
+ private final DefaultImeVisibilityApplier mVisibilityApplier;
/**
* Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
@@ -363,7 +366,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@MultiUserUnawareField
private int mDeviceIdToShowIme = DEVICE_ID_DEFAULT;
- @Nullable private StatusBarManagerInternal mStatusBarManagerInternal;
+ @Nullable
+ private StatusBarManagerInternal mStatusBarManagerInternal;
private boolean mShowOngoingImeSwitcherForPhones;
@GuardedBy("ImfLock.class")
@MultiUserUnawareField
@@ -538,7 +542,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* The {@link IRemoteAccessibilityInputConnection} last provided by the current client.
*/
@MultiUserUnawareField
- @Nullable IRemoteAccessibilityInputConnection mCurRemoteAccessibilityInputConnection;
+ @Nullable
+ IRemoteAccessibilityInputConnection mCurRemoteAccessibilityInputConnection;
/**
* The {@link EditorInfo} last provided by the current client.
@@ -804,7 +809,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mRegistered = true;
}
- @Override public void onChange(boolean selfChange, Uri uri) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
final Uri showImeUri = Settings.Secure.getUriFor(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
@@ -897,10 +903,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
for (int userId : mUserManagerInternal.getUserIds()) {
final InputMethodSettings settings = queryInputMethodServicesInternal(
- mContext,
- userId,
- AdditionalSubtypeMapRepository.get(userId),
- DirectBootAwareness.AUTO);
+ mContext,
+ userId,
+ AdditionalSubtypeMapRepository.get(userId),
+ DirectBootAwareness.AUTO);
InputMethodSettingsRepository.put(userId, settings);
}
postInputMethodSettingUpdatedLocked(true /* resetDefaultEnabledIme */);
@@ -1403,7 +1409,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mCurrentUserId = mActivityManagerInternal.getCurrentUserId();
@SuppressWarnings("GuardedBy") final IntFunction<InputMethodBindingController>
bindingControllerFactory = userId -> new InputMethodBindingController(userId,
- InputMethodManagerService.this);
+ InputMethodManagerService.this);
mUserDataRepository = new UserDataRepository(mHandler, mUserManagerInternal,
bindingControllerForTesting != null ? bindingControllerForTesting
: bindingControllerFactory);
@@ -2228,7 +2234,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mInputManagerInternal.notifyInputMethodConnectionActive(connectionIsActive);
}
final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
-
+ final var bindingController = userData.mBindingController;
// If configured, we want to avoid starting up the IME if it is not supposed to be showing
if (shouldPreventImeStartupLocked(selectedMethodId, startInputFlags,
@@ -2237,7 +2243,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
}
invalidateAutofillSessionLocked();
- userData.mBindingController.unbindCurrentMethod();
+ bindingController.unbindCurrentMethod();
return InputBindResult.NO_EDITOR;
}
@@ -2269,8 +2275,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
}
- userData.mBindingController.unbindCurrentMethod();
- return userData.mBindingController.bindCurrentMethod();
+ bindingController.unbindCurrentMethod();
+ return bindingController.bindCurrentMethod();
}
/**
@@ -2416,7 +2422,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@FunctionalInterface
interface ImeDisplayValidator {
- @DisplayImePolicy int getDisplayImePolicy(int displayId);
+ @DisplayImePolicy
+ int getDisplayImePolicy(int displayId);
}
/**
@@ -2711,7 +2718,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
: null;
if (mStatusBarManagerInternal != null) {
mStatusBarManagerInternal.setIcon(mSlotIme, packageName, iconId, 0,
- contentDescription != null
+ contentDescription != null
? contentDescription.toString() : null);
mStatusBarManagerInternal.setIconVisibility(mSlotIme, true);
}
@@ -4705,7 +4712,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
SparseArray<IAccessibilityInputMethodSession> disabledSessions = new SparseArray<>();
for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
if (!accessibilitySessions.contains(mEnabledAccessibilitySessions.keyAt(i))) {
- AccessibilitySessionState sessionState = mEnabledAccessibilitySessions.valueAt(i);
+ AccessibilitySessionState sessionState = mEnabledAccessibilitySessions.valueAt(i);
if (sessionState != null) {
disabledSessions.append(mEnabledAccessibilitySessions.keyAt(i),
sessionState.mSession);
@@ -5440,7 +5447,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
if (!settings.getMethodMap().containsKey(imeId)
|| !settings.getEnabledInputMethodList().contains(
- settings.getMethodMap().get(imeId))) {
+ settings.getMethodMap().get(imeId))) {
return false; // IME is not found or not enabled.
}
settings.putSelectedInputMethod(imeId);
@@ -6583,6 +6590,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private final InputMethodManagerService mImms;
@NonNull
private final IBinder mToken;
+
InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
@NonNull IBinder token) {
mImms = imms;
@@ -6611,8 +6619,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void createInputContentUriToken(Uri contentUri, String packageName,
AndroidFuture future /* T=IBinder */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<IBinder> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<IBinder> typedFuture = future;
try {
typedFuture.complete(mImms.createInputContentUriToken(
mToken, contentUri, packageName).asBinder());
@@ -6630,8 +6637,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
@Override
public void setInputMethod(String id, AndroidFuture future /* T=Void */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Void> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<Void> typedFuture = future;
try {
mImms.setInputMethod(mToken, id);
typedFuture.complete(null);
@@ -6644,8 +6650,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype,
AndroidFuture future /* T=Void */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Void> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<Void> typedFuture = future;
try {
mImms.setInputMethodAndSubtype(mToken, id, subtype);
typedFuture.complete(null);
@@ -6659,8 +6664,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
public void hideMySoftInput(@NonNull ImeTracker.Token statsToken,
@InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason,
AndroidFuture future /* T=Void */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Void> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<Void> typedFuture = future;
try {
mImms.hideMySoftInput(mToken, statsToken, flags, reason);
typedFuture.complete(null);
@@ -6674,8 +6678,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
public void showMySoftInput(@NonNull ImeTracker.Token statsToken,
@InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason,
AndroidFuture future /* T=Void */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Void> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<Void> typedFuture = future;
try {
mImms.showMySoftInput(mToken, statsToken, flags, reason);
typedFuture.complete(null);
@@ -6693,8 +6696,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
@Override
public void switchToPreviousInputMethod(AndroidFuture future /* T=Boolean */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Boolean> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<Boolean> typedFuture = future;
try {
typedFuture.complete(mImms.switchToPreviousInputMethod(mToken));
} catch (Throwable e) {
@@ -6706,8 +6708,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@Override
public void switchToNextInputMethod(boolean onlyCurrentIme,
AndroidFuture future /* T=Boolean */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Boolean> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<Boolean> typedFuture = future;
try {
typedFuture.complete(mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
} catch (Throwable e) {
@@ -6718,8 +6719,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
@BinderThread
@Override
public void shouldOfferSwitchingToNextInputMethod(AndroidFuture future /* T=Boolean */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Boolean> typedFuture = future;
+ @SuppressWarnings("unchecked") final AndroidFuture<Boolean> typedFuture = future;
try {
typedFuture.complete(mImms.shouldOfferSwitchingToNextInputMethod(mToken));
} catch (Throwable e) {
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 573116105dea..d6d134d892f5 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -78,10 +78,14 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
+import java.util.PriorityQueue;
+import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
/**
@@ -152,6 +156,16 @@ public class ContextHubService extends IContextHubService.Stub {
private final ScheduledThreadPoolExecutor mDailyMetricTimer =
new ScheduledThreadPoolExecutor(1);
+ // A queue of reliable message records for duplicate detection
+ private final PriorityQueue<ReliableMessageRecord> mReliableMessageRecordQueue =
+ new PriorityQueue<ReliableMessageRecord>(
+ (ReliableMessageRecord left, ReliableMessageRecord right) -> {
+ return Long.compare(left.getTimestamp(), right.getTimestamp());
+ });
+
+ // The test mode manager that manages behaviors during test mode.
+ private final TestModeManager mTestModeManager = new TestModeManager();
+
// The period of the recurring time
private static final int PERIOD_METRIC_QUERY_DAYS = 1;
@@ -164,6 +178,9 @@ public class ContextHubService extends IContextHubService.Stub {
private boolean mIsBtScanningEnabled = false;
private boolean mIsBtMainEnabled = false;
+ // True if test mode is enabled for the Context Hub
+ private AtomicBoolean mIsTestModeEnabled = new AtomicBoolean(false);
+
// A hashmap used to record if a contexthub is waiting for daily query
private Set<Integer> mMetricQueryPendingContextHubIds =
Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
@@ -210,8 +227,17 @@ public class ContextHubService extends IContextHubService.Stub {
@Override
public void handleNanoappMessage(short hostEndpointId, NanoAppMessage message,
List<String> nanoappPermissions, List<String> messagePermissions) {
- handleClientMessageCallback(mContextHubId, hostEndpointId, message, nanoappPermissions,
- messagePermissions);
+ if (Flags.reliableMessageImplementation()
+ && Flags.reliableMessageTestModeBehavior()
+ && mIsTestModeEnabled.get()
+ && mTestModeManager.handleNanoappMessage(mContextHubId, hostEndpointId,
+ message, nanoappPermissions, messagePermissions)) {
+ // The TestModeManager handled the nanoapp message, so return here.
+ return;
+ }
+
+ handleClientMessageCallback(mContextHubId, hostEndpointId, message,
+ nanoappPermissions, messagePermissions);
}
@Override
@@ -228,6 +254,106 @@ public class ContextHubService extends IContextHubService.Stub {
}
}
+ /**
+ * Records a reliable message from a nanoapp for duplicate detection.
+ */
+ private static class ReliableMessageRecord {
+ public static final int TIMEOUT_NS = 1000000000;
+
+ public int mContextHubId;
+ public long mTimestamp;
+ public int mMessageSequenceNumber;
+ byte mErrorCode;
+
+ ReliableMessageRecord(int contextHubId, long timestamp,
+ int messageSequenceNumber, byte errorCode) {
+ mContextHubId = contextHubId;
+ mTimestamp = timestamp;
+ mMessageSequenceNumber = messageSequenceNumber;
+ mErrorCode = errorCode;
+ }
+
+ public int getContextHubId() {
+ return mContextHubId;
+ }
+
+ public long getTimestamp() {
+ return mTimestamp;
+ }
+
+ public int getMessageSequenceNumber() {
+ return mMessageSequenceNumber;
+ }
+
+ public byte getErrorCode() {
+ return mErrorCode;
+ }
+
+ public void setErrorCode(byte errorCode) {
+ mErrorCode = errorCode;
+ }
+
+ public boolean isExpired() {
+ return mTimestamp + TIMEOUT_NS < SystemClock.elapsedRealtimeNanos();
+ }
+ }
+
+ /**
+ * A class to manage behaviors during test mode. This is used for testing.
+ */
+ private class TestModeManager {
+ /**
+ * Probability (in percent) of duplicating a message.
+ */
+ private static final int MESSAGE_DUPLICATION_PROBABILITY_PERCENT = 50;
+
+ /**
+ * The number of total messages to send when the duplicate event happens.
+ */
+ private static final int NUM_MESSAGES_TO_DUPLICATE = 3;
+
+ /**
+ * A probability percent for a certain event.
+ */
+ private static final int MAX_PROBABILITY_PERCENT = 100;
+
+ /**
+ * Random number generator.
+ */
+ private Random mRandom = new Random();
+
+ /**
+ * @see ContextHubServiceCallback.handleNanoappMessage
+ * @return whether the message was handled
+ */
+ public boolean handleNanoappMessage(int contextHubId,
+ short hostEndpointId, NanoAppMessage message,
+ List<String> nanoappPermissions, List<String> messagePermissions) {
+ if (!message.isReliable()) {
+ return false;
+ }
+
+ if (didEventHappen(MESSAGE_DUPLICATION_PROBABILITY_PERCENT)) {
+ for (int i = 0; i < NUM_MESSAGES_TO_DUPLICATE; ++i) {
+ handleClientMessageCallback(contextHubId, hostEndpointId,
+ message, nanoappPermissions, messagePermissions);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the event with percentPercent did happen.
+ *
+ * @param probabilityPercent the percent probability of the event.
+ * @return true if the event happened, false otherwise.
+ */
+ private boolean didEventHappen(int probabilityPercent) {
+ return mRandom.nextInt(MAX_PROBABILITY_PERCENT) < probabilityPercent;
+ }
+ }
+
public ContextHubService(Context context, IContextHubWrapper contextHubWrapper) {
Log.i(TAG, "Starting Context Hub Service init");
mContext = context;
@@ -563,6 +689,8 @@ public class ContextHubService extends IContextHubService.Stub {
* Resets the settings. Called when a context hub restarts or the AIDL HAL dies
*/
private void resetSettings() {
+ mIsTestModeEnabled.set(false);
+
sendLocationSettingUpdate();
sendWifiSettingUpdate(/* forceUpdate= */ true);
sendAirplaneModeSettingUpdate();
@@ -854,14 +982,76 @@ public class ContextHubService extends IContextHubService.Stub {
private void handleClientMessageCallback(int contextHubId, short hostEndpointId,
NanoAppMessage message, List<String> nanoappPermissions,
List<String> messagePermissions) {
- byte errorCode = mClientManager.onMessageFromNanoApp(contextHubId, hostEndpointId, message,
- nanoappPermissions, messagePermissions);
- if (message.isReliable() && errorCode != ErrorCode.OK) {
- sendMessageDeliveryStatusToContextHub(contextHubId, message.getMessageSequenceNumber(),
- errorCode);
+ if (!Flags.reliableMessageImplementation()
+ || !Flags.reliableMessageDuplicateDetectionService()) {
+ byte errorCode = mClientManager.onMessageFromNanoApp(contextHubId, hostEndpointId,
+ message, nanoappPermissions, messagePermissions);
+ if (message.isReliable() && errorCode != ErrorCode.OK) {
+ sendMessageDeliveryStatusToContextHub(contextHubId,
+ message.getMessageSequenceNumber(), errorCode);
+ }
+ return;
+ }
+
+ if (message.isReliable()) {
+ byte errorCode = ErrorCode.OK;
+ synchronized (mReliableMessageRecordQueue) {
+ Optional<ReliableMessageRecord> record = Optional.empty();
+ for (ReliableMessageRecord r: mReliableMessageRecordQueue) {
+ if (r.getContextHubId() == contextHubId
+ && r.getMessageSequenceNumber() == message.getMessageSequenceNumber()) {
+ record = Optional.of(r);
+ break;
+ }
+ }
+
+ if (record.isPresent()) {
+ errorCode = record.get().getErrorCode();
+ if (errorCode == ErrorCode.TRANSIENT_ERROR) {
+ Log.w(TAG, "Found duplicate reliable message with message sequence number: "
+ + record.get().getMessageSequenceNumber() + ": retrying");
+ errorCode = mClientManager.onMessageFromNanoApp(
+ contextHubId, hostEndpointId, message,
+ nanoappPermissions, messagePermissions);
+ record.get().setErrorCode(errorCode);
+ } else {
+ Log.w(TAG, "Found duplicate reliable message with message sequence number: "
+ + record.get().getMessageSequenceNumber());
+ }
+ } else {
+ errorCode = mClientManager.onMessageFromNanoApp(
+ contextHubId, hostEndpointId, message,
+ nanoappPermissions, messagePermissions);
+ mReliableMessageRecordQueue.add(
+ new ReliableMessageRecord(contextHubId,
+ SystemClock.elapsedRealtimeNanos(),
+ message.getMessageSequenceNumber(),
+ errorCode));
+ }
+ }
+ sendMessageDeliveryStatusToContextHub(contextHubId,
+ message.getMessageSequenceNumber(), errorCode);
+ } else {
+ mClientManager.onMessageFromNanoApp(
+ contextHubId, hostEndpointId, message,
+ nanoappPermissions, messagePermissions);
+ }
+
+ synchronized (mReliableMessageRecordQueue) {
+ while (mReliableMessageRecordQueue.peek() != null
+ && mReliableMessageRecordQueue.peek().isExpired()) {
+ mReliableMessageRecordQueue.poll();
+ }
}
}
+ /**
+ * Sends the message delivery status to the Context Hub.
+ *
+ * @param contextHubId the ID of the hub
+ * @param messageSequenceNumber the message sequence number
+ * @param errorCode the error code, one of the enum ErrorCode
+ */
private void sendMessageDeliveryStatusToContextHub(int contextHubId,
int messageSequenceNumber, byte errorCode) {
if (!Flags.reliableMessageImplementation()) {
@@ -1229,6 +1419,9 @@ public class ContextHubService extends IContextHubService.Stub {
public boolean setTestMode(boolean enable) {
super.setTestMode_enforcePermission();
boolean status = mContextHubWrapper.setTestMode(enable);
+ if (status) {
+ mIsTestModeEnabled.set(enable);
+ }
// Query nanoapps to update service state after test mode state change.
for (int contextHubId: mDefaultClientMap.keySet()) {
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 869b89a6670c..73647dbbe978 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1305,22 +1305,20 @@ class MediaRouter2ServiceImpl {
route.getId(),
requestId));
+ UserHandler userHandler = routerRecord.mUserRecord.mHandler;
if (managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE) {
- ManagerRecord manager = routerRecord.mUserRecord.mHandler.findManagerWithId(
- toRequesterId(managerRequestId));
+ ManagerRecord manager = userHandler.findManagerWithId(toRequesterId(managerRequestId));
if (manager == null || manager.mLastSessionCreationRequest == null) {
Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+ "Ignoring unknown request.");
- routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
- routerRecord, requestId);
+ userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
return;
}
if (!TextUtils.equals(manager.mLastSessionCreationRequest.mOldSession.getId(),
oldSession.getId())) {
Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+ "Ignoring unmatched routing session.");
- routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
- routerRecord, requestId);
+ userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
return;
}
if (!TextUtils.equals(manager.mLastSessionCreationRequest.mRoute.getId(),
@@ -1333,29 +1331,28 @@ class MediaRouter2ServiceImpl {
} else {
Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+ "Ignoring unmatched route.");
- routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
- routerRecord, requestId);
+ userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
return;
}
}
manager.mLastSessionCreationRequest = null;
} else {
+ String defaultRouteId = userHandler.mSystemProvider.getDefaultRoute().getId();
if (route.isSystemRoute()
&& !routerRecord.hasSystemRoutingPermission()
- && !TextUtils.equals(route.getId(), MediaRoute2Info.ROUTE_ID_DEFAULT)) {
+ && !TextUtils.equals(route.getId(), defaultRouteId)) {
Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
+ route);
- routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
- routerRecord, requestId);
+ userHandler.notifySessionCreationFailedToRouter(routerRecord, requestId);
return;
}
}
long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
- routerRecord.mUserRecord.mHandler.sendMessage(
+ userHandler.sendMessage(
obtainMessage(
UserHandler::requestCreateSessionWithRouter2OnHandler,
- routerRecord.mUserRecord.mHandler,
+ userHandler,
uniqueRequestId,
managerRequestId,
transferInitiatorUserHandle,
@@ -1429,18 +1426,22 @@ class MediaRouter2ServiceImpl {
"transferToRouteWithRouter2 | router: %s(id: %d), route: %s",
routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
+ UserHandler userHandler = routerRecord.mUserRecord.mHandler;
+ String defaultRouteId = userHandler.mSystemProvider.getDefaultRoute().getId();
if (route.isSystemRoute()
&& !routerRecord.hasSystemRoutingPermission()
- && !TextUtils.equals(route.getId(), MediaRoute2Info.ROUTE_ID_DEFAULT)) {
- routerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::notifySessionCreationFailedToRouter,
- routerRecord.mUserRecord.mHandler,
- routerRecord, toOriginalRequestId(DUMMY_REQUEST_ID)));
+ && !TextUtils.equals(route.getId(), defaultRouteId)) {
+ userHandler.sendMessage(
+ obtainMessage(
+ UserHandler::notifySessionCreationFailedToRouter,
+ userHandler,
+ routerRecord,
+ toOriginalRequestId(DUMMY_REQUEST_ID)));
} else {
- routerRecord.mUserRecord.mHandler.sendMessage(
+ userHandler.sendMessage(
obtainMessage(
UserHandler::transferToRouteOnHandler,
- routerRecord.mUserRecord.mHandler,
+ userHandler,
DUMMY_REQUEST_ID,
transferInitiatorUserHandle,
routerRecord.mPackageName,
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index c105b9c37026..6ce3ab4b2d65 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -232,10 +232,16 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
String sessionId,
String routeId,
@RoutingSessionInfo.TransferReason int transferReason) {
+ String selectedDeviceRouteId = mDeviceRouteController.getSelectedRoute().getId();
if (TextUtils.equals(routeId, MediaRoute2Info.ROUTE_ID_DEFAULT)) {
- // The currently selected route is the default route.
- Log.w(TAG, "Ignoring transfer to " + MediaRoute2Info.ROUTE_ID_DEFAULT);
- return;
+ if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
+ // Transfer to the default route (which is the selected route). We replace the id to
+ // be the selected route id so that the transfer reason gets updated.
+ routeId = selectedDeviceRouteId;
+ } else {
+ Log.w(TAG, "Ignoring transfer to " + MediaRoute2Info.ROUTE_ID_DEFAULT);
+ return;
+ }
}
if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
@@ -250,11 +256,11 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
}
- MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute();
+ String finalRouteId = routeId; // Make a final copy to use it in the lambda.
boolean isAvailableDeviceRoute =
mDeviceRouteController.getAvailableRoutes().stream()
- .anyMatch(it -> it.getId().equals(routeId));
- boolean isSelectedDeviceRoute = TextUtils.equals(routeId, selectedDeviceRoute.getId());
+ .anyMatch(it -> it.getId().equals(finalRouteId));
+ boolean isSelectedDeviceRoute = TextUtils.equals(routeId, selectedDeviceRouteId);
if (isSelectedDeviceRoute || isAvailableDeviceRoute) {
// The requested route is managed by the device route controller. Note that the selected
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3dd2f1eb5123..42ec1c3ad4ed 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -245,7 +245,6 @@ import android.os.DeadObjectException;
import android.os.DeviceIdleManager;
import android.os.Environment;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IInterface;
@@ -2038,19 +2037,21 @@ public class NotificationManagerService extends SystemService {
mSnoozeHelper.clearData(userHandle);
}
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
- mUserProfiles.updateCache(context);
- if (!mUserProfiles.isProfileUser(userId, context)) {
- // reload per-user settings
- mSettingsObserver.update(null);
- // Refresh managed services
- mConditionProviders.onUserSwitched(userId);
- mListeners.onUserSwitched(userId);
- mZenModeHelper.onUserSwitched(userId);
- mPreferencesHelper.syncChannelsBypassingDnd();
- }
- // assistant is the only thing that cares about managed profiles specifically
- mAssistants.onUserSwitched(userId);
+ if (!Flags.useSsmUserSwitchSignal()) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+ mUserProfiles.updateCache(context);
+ if (!mUserProfiles.isProfileUser(userId, context)) {
+ // reload per-user settings
+ mSettingsObserver.update(null);
+ // Refresh managed services
+ mConditionProviders.onUserSwitched(userId);
+ mListeners.onUserSwitched(userId);
+ mZenModeHelper.onUserSwitched(userId);
+ mPreferencesHelper.syncChannelsBypassingDnd();
+ }
+ // assistant is the only thing that cares about managed profiles specifically
+ mAssistants.onUserSwitched(userId);
+ }
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
if (userId != USER_NULL) {
@@ -2570,7 +2571,9 @@ public class NotificationManagerService extends SystemService {
// calling onDestroy()
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_STOPPED);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
+ if (!Flags.useSsmUserSwitchSignal()) {
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ }
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
@@ -2966,6 +2969,26 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ if (!Flags.useSsmUserSwitchSignal()) {
+ return;
+ }
+ final int userId = to.getUserIdentifier();
+ mUserProfiles.updateCache(getContext());
+ if (!mUserProfiles.isProfileUser(userId, getContext())) {
+ // reload per-user settings
+ mSettingsObserver.update(null);
+ // Refresh managed services
+ mConditionProviders.onUserSwitched(userId);
+ mListeners.onUserSwitched(userId);
+ mZenModeHelper.onUserSwitched(userId);
+ mPreferencesHelper.syncChannelsBypassingDnd();
+ }
+ // assistant is the only thing that cares about managed profiles specifically
+ mAssistants.onUserSwitched(userId);
+ }
+
+ @Override
public void onUserStopping(@NonNull TargetUser user) {
mHandler.post(() -> {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser");
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 143bc5cb20ff..b589f4972155 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -486,6 +486,7 @@ public class ZenModeHelper {
}
}
+ @GuardedBy("mConfigLock")
private ZenRule maybeRestoreRemovedRule(ZenModeConfig config, ZenRule ruleToAdd,
AutomaticZenRule azrToAdd, @ConfigChangeOrigin int origin) {
if (!Flags.modesApi()) {
@@ -1112,6 +1113,7 @@ public class ZenModeHelper {
* <p>The rule's {@link ZenRule#condition} is cleared (meaning that an active rule will be
* deactivated) unless the update has origin == {@link ZenModeConfig#UPDATE_ORIGIN_USER}.
*/
+ @GuardedBy("mConfigLock")
private boolean populateZenRule(String pkg, AutomaticZenRule azr, ZenRule rule,
@ConfigChangeOrigin int origin, boolean isNew) {
if (Flags.modesApi()) {
@@ -1261,12 +1263,14 @@ public class ZenModeHelper {
*
* <p>Returns {@code true} if the policy of the rule was modified.
*/
+ @GuardedBy("mConfigLock")
private boolean updatePolicy(ZenRule zenRule, @Nullable ZenPolicy newPolicy,
boolean updateBitmask, boolean isNew) {
if (newPolicy == null) {
if (isNew) {
// Newly created rule with no provided policy; fill in with the default.
- zenRule.zenPolicy = mDefaultConfig.toZenPolicy();
+ zenRule.zenPolicy =
+ Flags.modesUi() ? mDefaultConfig.toZenPolicy() : mConfig.toZenPolicy();
return true;
}
// Otherwise, a null policy means no policy changes, so we can stop here.
@@ -1275,8 +1279,9 @@ public class ZenModeHelper {
// If oldPolicy is null, we compare against the default policy when determining which
// fields in the bitmask should be marked as updated.
- ZenPolicy oldPolicy =
- zenRule.zenPolicy != null ? zenRule.zenPolicy : mDefaultConfig.toZenPolicy();
+ ZenPolicy oldPolicy = zenRule.zenPolicy != null
+ ? zenRule.zenPolicy
+ : (Flags.modesUi() ? mDefaultConfig.toZenPolicy() : mConfig.toZenPolicy());
// If this is updating a rule rather than creating a new one, keep any fields from the
// old policy if they are unspecified in the new policy. For newly created rules, oldPolicy
@@ -2033,7 +2038,8 @@ public class ZenModeHelper {
// rule's policy fields should be set upon creation, this is a fallback to
// catch any that may have fallen through the cracks.
Log.wtf(TAG, "active automatic rule found with no specified policy: " + rule);
- policy.apply(mDefaultConfig.toZenPolicy());
+ policy.apply(
+ Flags.modesUi() ? mDefaultConfig.toZenPolicy() : mConfig.toZenPolicy());
}
} else {
// active rule with no specified policy inherits the global config settings
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index af3db6c6be4f..9dcca494ca24 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -128,3 +128,10 @@ flag {
description: "Adds an IPCDataCache for notification channel/group lookups"
bug: "331677193"
}
+
+flag {
+ name: "use_ssm_user_switch_signal"
+ namespace: "systemui"
+ description: "This flag controls which signal is used to handle a user switch system event"
+ bug: "337077643"
+}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 8a853287738b..71a7d0d2a638 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -46,6 +46,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.LocalLog;
+import android.util.MutableBoolean;
import android.util.Pair;
import android.util.Slog;
import android.util.Xml;
@@ -104,6 +105,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
private final TelephonyManager mTelephonyManager;
private final ArraySet<String> mBugreportAllowlistedPackages;
private final BugreportFileManager mBugreportFileManager;
+ private static final FeatureFlags sFeatureFlags = new FeatureFlagsImpl();
@GuardedBy("mLock")
@@ -429,9 +431,51 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
ensureUserCanTakeBugReport(bugreportMode);
Slogf.i(TAG, "Starting bugreport for %s / %d", callingPackage, callingUid);
- synchronized (mLock) {
- startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
- bugreportMode, bugreportFlags, listener, isScreenshotRequested);
+ final MutableBoolean handoffLock = new MutableBoolean(false);
+ if (sFeatureFlags.asyncStartBugreport()) {
+ synchronized (handoffLock) {
+ new Thread(()-> {
+ try {
+ synchronized (mLock) {
+ synchronized (handoffLock) {
+ handoffLock.value = true;
+ handoffLock.notifyAll();
+ }
+ startBugreportLocked(
+ callingUid,
+ callingPackage,
+ bugreportFd,
+ screenshotFd,
+ bugreportMode,
+ bugreportFlags,
+ listener,
+ isScreenshotRequested);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Cannot start a new bugreport due to an unknown error", e);
+ reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+ }
+ }, "BugreportManagerServiceThread").start();
+ try {
+ while (!handoffLock.value) { // handle the rare case of a spurious wakeup
+ handoffLock.wait(DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS);
+ }
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Unexpectedly interrupted waiting for startBugreportLocked", e);
+ }
+ }
+ } else {
+ synchronized (mLock) {
+ startBugreportLocked(
+ callingUid,
+ callingPackage,
+ bugreportFd,
+ screenshotFd,
+ bugreportMode,
+ bugreportFlags,
+ listener,
+ isScreenshotRequested);
+ }
}
}
diff --git a/services/core/java/com/android/server/os/core_os_flags.aconfig b/services/core/java/com/android/server/os/core_os_flags.aconfig
index ae33df83e3aa..efdc9b8c164f 100644
--- a/services/core/java/com/android/server/os/core_os_flags.aconfig
+++ b/services/core/java/com/android/server/os/core_os_flags.aconfig
@@ -7,3 +7,13 @@ flag {
description: "Use proto tombstones as source of truth for adding to dropbox"
bug: "323857385"
}
+
+flag {
+ name: "async_start_bugreport"
+ namespace: "crumpet"
+ description: "Don't block callers on the start of dumpsys service"
+ bug: "180123623"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 3862b79eb780..5ac883c58f03 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -688,6 +688,29 @@ public class DefaultCrossProfileIntentFiltersUtils {
);
}
+ /** Call intent should be handled by the main user. */
+ private static final DefaultCrossProfileIntentFilter CALL_PRIVATE_PROFILE =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
+ SKIP_CURRENT_PROFILE,
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(Intent.ACTION_CALL)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addDataScheme("tel")
+ .addDataScheme("sip")
+ .addDataScheme("voicemail")
+ .build();
+
+ /** Pressing the call button should be handled by the main user. */
+ private static final DefaultCrossProfileIntentFilter CALL_BUTTON_PRIVATE_PROFILE =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
+ ONLY_IF_NO_MATCH_FOUND,
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(Intent.ACTION_CALL_BUTTON)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .build();
+
/** Dial intent with mime type can be handled by either private profile or its parent user. */
private static final DefaultCrossProfileIntentFilter DIAL_MIME_PRIVATE_PROFILE =
new DefaultCrossProfileIntentFilter.Builder(
@@ -755,6 +778,10 @@ public class DefaultCrossProfileIntentFiltersUtils {
DIAL_MIME_PRIVATE_PROFILE,
DIAL_DATA_PRIVATE_PROFILE,
DIAL_RAW_PRIVATE_PROFILE,
+ CALL_PRIVATE_PROFILE,
+ CALL_BUTTON_PRIVATE_PROFILE,
+ EMERGENCY_CALL_DATA,
+ EMERGENCY_CALL_MIME,
SMS_MMS_PRIVATE_PROFILE
);
}
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index c60f0afcc2ff..209cbb7f591e 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -46,6 +46,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApexStagedEvent;
+import android.content.pm.Flags;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageManager;
@@ -766,6 +767,10 @@ public final class DexOptHelper {
final PackageSetting ps = installRequest.getScannedPackageSetting();
final AndroidPackage pkg = ps.getPkg();
final boolean onIncremental = isIncrementalPath(ps.getPathString());
+ final boolean performDexOptForRollback = Flags.recoverabilityDetection()
+ ? !(installRequest.isRollback()
+ && installRequest.getInstallSource().mInitiatingPackageName.equals("android"))
+ : true;
return (!instantApp || Global.getInt(context.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
@@ -773,7 +778,8 @@ public final class DexOptHelper {
&& !pkg.isDebuggable()
&& (!onIncremental)
&& dexoptOptions.isCompilationEnabled()
- && !isApex;
+ && !isApex
+ && performDexOptForRollback;
}
private static class StagedApexObserver extends IStagedApexObserver.Stub {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index fa54f6e69b19..b369f03d002f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -1667,15 +1667,6 @@ public class PackageManagerServiceUtils {
if (appMetadataFile.exists()) {
return true;
}
- if (isSystem) {
- try {
- makeDirRecursive(new File(appMetadataFilePath).getParentFile(), 0700);
- } catch (Exception e) {
- Slog.e(TAG, "Failed to create app metadata dir for package "
- + pkg.getPackageName() + ": " + e.getMessage());
- return false;
- }
- }
Map<String, Property> properties = pkg.getProperties();
if (!properties.containsKey(PROPERTY_ANDROID_SAFETY_LABEL_PATH)) {
return false;
@@ -1684,6 +1675,15 @@ public class PackageManagerServiceUtils {
if (!fileInAPkPathProperty.isString()) {
return false;
}
+ if (isSystem && !appMetadataFile.getParentFile().exists()) {
+ try {
+ makeDirRecursive(appMetadataFile.getParentFile(), 0700);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to create app metadata dir for package "
+ + pkg.getPackageName() + ": " + e.getMessage());
+ return false;
+ }
+ }
String fileInApkPath = fileInAPkPathProperty.getString();
List<AndroidPackageSplit> splits = pkg.getSplits();
for (int i = 0; i < splits.size(); i++) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 82902d45f1f2..9edf3b14bad7 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -172,7 +172,7 @@ public class ShortcutService extends IShortcutService.Stub {
static final boolean DEBUG = false; // STOPSHIP if true
static final boolean DEBUG_LOAD = false; // STOPSHIP if true
static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true
- static final boolean DEBUG_REBOOT = false; // STOPSHIP if true
+ static final boolean DEBUG_REBOOT = true;
@VisibleForTesting
static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
@@ -3798,24 +3798,36 @@ public class ShortcutService extends IShortcutService.Stub {
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
final boolean archival = intent.getBooleanExtra(Intent.EXTRA_ARCHIVAL, false);
+ Slog.d(TAG, "received package broadcast intent: " + intent);
switch (action) {
case Intent.ACTION_PACKAGE_ADDED:
if (replacing) {
+ Slog.d(TAG, "replacing package: " + packageName + " userId" + userId);
handlePackageUpdateFinished(packageName, userId);
} else {
+ Slog.d(TAG, "adding package: " + packageName + " userId" + userId);
handlePackageAdded(packageName, userId);
}
break;
case Intent.ACTION_PACKAGE_REMOVED:
if (!replacing || (replacing && archival)) {
+ if (!replacing) {
+ Slog.d(TAG, "removing package: "
+ + packageName + " userId" + userId);
+ } else if (archival) {
+ Slog.d(TAG, "archiving package: "
+ + packageName + " userId" + userId);
+ }
handlePackageRemoved(packageName, userId);
}
break;
case Intent.ACTION_PACKAGE_CHANGED:
+ Slog.d(TAG, "changing package: " + packageName + " userId" + userId);
handlePackageChanged(packageName, userId);
-
break;
case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ Slog.d(TAG, "clearing data for package: "
+ + packageName + " userId" + userId);
handlePackageDataCleared(packageName, userId);
break;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3c702b4125b7..f6487ceea43b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1371,7 +1371,7 @@ public class UserManagerService extends IUserManager.Stub {
for (int i = 0; i < userSize; i++) {
UserInfo ui = mUsers.valueAt(i).info;
if ((excludePartial && ui.partial)
- || (excludeDying && mRemovingUserIds.get(ui.id))
+ || (excludeDying && isDyingLU(ui))
|| (excludePreCreated && ui.preCreated)) {
continue;
}
@@ -1381,6 +1381,17 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ @GuardedBy("mUsersLock")
+ private boolean isDyingLU(UserInfo ui) {
+ if (mRemovingUserIds.get(ui.id)) {
+ return true;
+ }
+ if (ui.isEphemeral() && ui.isInitialized() && ui.id != getCurrentUserId()) {
+ return true;
+ }
+ return false;
+ }
+
@Override
public List<UserInfo> getProfiles(@UserIdInt int userId, boolean enabledOnly) {
boolean returnFullInfo;
@@ -7155,6 +7166,7 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mUsersLock) {
pw.println(" Boot user: " + mBootUser);
}
+ pw.println("Can add private profile: "+ canAddPrivateProfile(currentUserId));
pw.println();
pw.println("Number of listeners for");
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 1a9e012a7c53..f7eb29fe3ee9 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -141,6 +141,8 @@ final class VerifyingSession {
@NonNull
private final PackageManagerService mPm;
+ private final int mInstallReason;
+
VerifyingSession(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
PackageInstaller.SessionParams sessionParams, InstallSource installSource,
int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite,
@@ -168,6 +170,7 @@ final class VerifyingSession {
mUserActionRequiredType = sessionParams.requireUserAction;
mIsInherit = sessionParams.mode == MODE_INHERIT_EXISTING;
mIsStaged = sessionParams.isStaged;
+ mInstallReason = sessionParams.installReason;
}
@Override
@@ -190,7 +193,9 @@ final class VerifyingSession {
// Perform package verification and enable rollback (unless we are simply moving the
// package).
if (!mOriginInfo.mExisting) {
- if (!isApex() && !isArchivedInstallation()) {
+ final boolean verifyForRollback = Flags.recoverabilityDetection()
+ ? !isARollback() : true;
+ if (!isApex() && !isArchivedInstallation() && verifyForRollback) {
// TODO(b/182426975): treat APEX as APK when APK verification is concerned
sendApkVerificationRequest(pkgLite);
}
@@ -200,6 +205,11 @@ final class VerifyingSession {
}
}
+ private boolean isARollback() {
+ return mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK
+ && mInstallSource.mInitiatingPackageName.equals("android");
+ }
+
private void sendApkVerificationRequest(PackageInfoLite pkgLite) {
final int verificationId = mPm.mPendingVerificationToken++;
diff --git a/services/core/java/com/android/server/power/batterysaver/flags.aconfig b/services/core/java/com/android/server/power/batterysaver/flags.aconfig
index 059c4a491e31..1dea5239dbe5 100644
--- a/services/core/java/com/android/server/power/batterysaver/flags.aconfig
+++ b/services/core/java/com/android/server/power/batterysaver/flags.aconfig
@@ -3,7 +3,7 @@ container: "system"
flag {
name: "update_auto_turn_on_notification_string_and_action"
- namespace: "power_optimization"
+ namespace: "backstage_power"
description: "Improve the string and hightligh settings item for battery saver auto-turn-on notification"
bug: "336960905"
metadata {
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 4ddd54623e8c..267ddd07fd32 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.power.hint;
+import static android.os.Flags.adpfUseFmqChannel;
+
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.android.server.power.hint.Flags.powerhintThreadCleanup;
@@ -26,6 +28,8 @@ import android.app.ActivityManagerInternal;
import android.app.StatsManager;
import android.app.UidObserver;
import android.content.Context;
+import android.hardware.power.ChannelConfig;
+import android.hardware.power.IPower;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
import android.hardware.power.WorkDuration;
@@ -39,6 +43,7 @@ import android.os.Message;
import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -69,6 +74,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
+import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -91,9 +97,21 @@ public final class HintManagerService extends SystemService {
@GuardedBy("mLock")
private final ArrayMap<Integer, ArrayMap<IBinder, ArraySet<AppHintSession>>> mActiveSessions;
+ // Multi-level map storing all the channel binder token death listeners.
+ // First level is keyed by the UID of the client process owning the channel.
+ // Second level is the tgid of the process, which will often just be size one.
+ // Each channel is unique per (tgid, uid) pair, so this map associates each pair with an
+ // object that listens for the death notification of the binder token that was provided by
+ // that client when it created the channel, so we can detect when the client process dies.
+ @GuardedBy("mChannelMapLock")
+ private ArrayMap<Integer, TreeMap<Integer, ChannelItem>> mChannelMap;
+
/** Lock to protect mActiveSessions and the UidObserver. */
private final Object mLock = new Object();
+ /** Lock to protect mChannelMap. */
+ private final Object mChannelMapLock = new Object();
+
@GuardedBy("mNonIsolatedTidsLock")
private final Map<Integer, Set<Long>> mNonIsolatedTids;
@@ -110,6 +128,9 @@ public final class HintManagerService extends SystemService {
private AtomicBoolean mConfigCreationSupport = new AtomicBoolean(true);
+ private final IPower mPowerHal;
+ private int mPowerHalVersion;
+
private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";
@@ -131,12 +152,22 @@ public final class HintManagerService extends SystemService {
mNonIsolatedTids = null;
}
mActiveSessions = new ArrayMap<>();
+ mChannelMap = new ArrayMap<>();
mNativeWrapper = injector.createNativeWrapper();
mNativeWrapper.halInit();
mHintSessionPreferredRate = mNativeWrapper.halGetHintSessionPreferredRate();
mUidObserver = new MyUidObserver();
mAmInternal = Objects.requireNonNull(
LocalServices.getService(ActivityManagerInternal.class));
+ mPowerHal = injector.createIPower();
+ mPowerHalVersion = 0;
+ if (mPowerHal != null) {
+ try {
+ mPowerHalVersion = mPowerHal.getInterfaceVersion();
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Could not contact PowerHAL!", e);
+ }
+ }
}
private ServiceThread createCleanUpThread() {
@@ -151,6 +182,10 @@ public final class HintManagerService extends SystemService {
NativeWrapper createNativeWrapper() {
return new NativeWrapper();
}
+ IPower createIPower() {
+ return IPower.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(IPower.DESCRIPTOR + "/default"));
+ }
}
private boolean isHalSupported() {
@@ -344,6 +379,16 @@ public final class HintManagerService extends SystemService {
}
}
}
+ synchronized (mChannelMapLock) {
+ // Clean up the uid's session channels
+ final TreeMap<Integer, ChannelItem> uidMap = mChannelMap.get(uid);
+ if (uidMap != null) {
+ for (Map.Entry<Integer, ChannelItem> entry : uidMap.entrySet()) {
+ entry.getValue().closeChannel();
+ }
+ mChannelMap.remove(uid);
+ }
+ }
});
}
@@ -383,6 +428,113 @@ public final class HintManagerService extends SystemService {
}
}
+ /**
+ * Creates a channel item in the channel map if one does not exist, then returns
+ * the entry in the channel map.
+ */
+ public ChannelItem getOrCreateMappedChannelItem(int tgid, int uid, IBinder token) {
+ synchronized (mChannelMapLock) {
+ if (!mChannelMap.containsKey(uid)) {
+ mChannelMap.put(uid, new TreeMap<Integer, ChannelItem>());
+ }
+ TreeMap<Integer, ChannelItem> map = mChannelMap.get(uid);
+ if (!map.containsKey(tgid)) {
+ ChannelItem item = new ChannelItem(tgid, uid, token);
+ item.openChannel();
+ map.put(tgid, item);
+ }
+ return map.get(tgid);
+ }
+ }
+
+ /**
+ * This removes an entry in the binder token callback map when a channel is closed,
+ * and unregisters its callbacks.
+ */
+ public void removeChannelItem(Integer tgid, Integer uid) {
+ synchronized (mChannelMapLock) {
+ TreeMap<Integer, ChannelItem> map = mChannelMap.get(uid);
+ if (map != null) {
+ ChannelItem item = map.get(tgid);
+ if (item != null) {
+ item.closeChannel();
+ map.remove(tgid);
+ }
+ if (map.isEmpty()) {
+ mChannelMap.remove(uid);
+ }
+ }
+ }
+ }
+
+ /**
+ * Manages the lifecycle of a single channel. This includes caching the channel descriptor,
+ * receiving binder token death notifications, and handling cleanup on uid termination. There
+ * can only be one ChannelItem per (tgid, uid) pair in mChannelMap, and channel creation happens
+ * when a ChannelItem enters the map, while destruction happens when it leaves the map.
+ */
+ private class ChannelItem implements IBinder.DeathRecipient {
+ @Override
+ public void binderDied() {
+ removeChannelItem(mTgid, mUid);
+ }
+
+ ChannelItem(int tgid, int uid, IBinder token) {
+ this.mTgid = tgid;
+ this.mUid = uid;
+ this.mToken = token;
+ this.mLinked = false;
+ this.mConfig = null;
+ }
+
+ public void closeChannel() {
+ if (mLinked) {
+ mToken.unlinkToDeath(this, 0);
+ mLinked = false;
+ }
+ if (mConfig != null) {
+ try {
+ mPowerHal.closeSessionChannel(mTgid, mUid);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to close session channel!", e);
+ }
+ mConfig = null;
+ }
+ }
+
+ public void openChannel() {
+ if (!mLinked) {
+ try {
+ mToken.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Client already dead", e);
+ }
+ mLinked = true;
+ }
+ if (mConfig == null) {
+ try {
+ // This method uses PowerHAL directly through the SDK,
+ // to avoid needing to pass the ChannelConfig through JNI.
+ mConfig = mPowerHal.getSessionChannel(mTgid, mUid);
+ } catch (RemoteException e) {
+ removeChannelItem(mTgid, mUid);
+ throw new IllegalStateException("Failed to create session channel!", e);
+ }
+ }
+ }
+
+ ChannelConfig getConfig() {
+ return mConfig;
+ }
+
+ // To avoid accidental double-linking / unlinking
+ boolean mLinked;
+ final int mTgid;
+ final int mUid;
+ final IBinder mToken;
+ ChannelConfig mConfig;
+ }
+
final class CleanUpHandler extends Handler {
// status of processed tid used for caching
private static final int TID_NOT_CHECKED = 0;
@@ -570,6 +722,18 @@ public final class HintManagerService extends SystemService {
return mService;
}
+ @VisibleForTesting
+ Boolean hasChannel(int tgid, int uid) {
+ synchronized (mChannelMapLock) {
+ TreeMap<Integer, ChannelItem> uidMap = mChannelMap.get(uid);
+ if (uidMap != null) {
+ ChannelItem item = uidMap.get(tgid);
+ return item != null;
+ }
+ return false;
+ }
+ }
+
// returns the first invalid tid or null if not found
private Integer checkTidValid(int uid, int tgid, int [] tids, IntArray nonIsolated) {
// Make sure all tids belongs to the same UID (including isolated UID),
@@ -710,6 +874,28 @@ public final class HintManagerService extends SystemService {
}
@Override
+ public ChannelConfig getSessionChannel(IBinder token) {
+ if (mPowerHalVersion < 5 || !adpfUseFmqChannel()) {
+ return null;
+ }
+ java.util.Objects.requireNonNull(token);
+ final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
+ final int callingUid = Binder.getCallingUid();
+ ChannelItem item = getOrCreateMappedChannelItem(callingTgid, callingUid, token);
+ return item.getConfig();
+ };
+
+ @Override
+ public void closeSessionChannel() {
+ if (mPowerHalVersion < 5 || !adpfUseFmqChannel()) {
+ return;
+ }
+ final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
+ final int callingUid = Binder.getCallingUid();
+ removeChannelItem(callingTgid, callingUid);
+ };
+
+ @Override
public long getHintSessionPreferredRate() {
return mHintSessionPreferredRate;
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
index 36192537493a..474253223628 100644
--- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
+++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -115,6 +115,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
// validation failure.
private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT = 12;
+ /** Carriers can disable the detector by setting the threshold to -1 */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR = -1;
+
private static final int POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT = 20;
// By default, there's no maximum limit enforced
@@ -271,7 +275,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
// When multiple parallel inbound transforms are created, NetworkMetricMonitor will be
// enabled on the last one as a sample
mInboundTransform = inboundTransform;
- start();
+
+ if (!Flags.allowDisableIpsecLossDetector() || canStart()) {
+ start();
+ }
}
@Override
@@ -284,6 +291,14 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig);
mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig);
}
+
+ if (Flags.allowDisableIpsecLossDetector() && canStart() != isStarted()) {
+ if (canStart()) {
+ start();
+ } else {
+ stop();
+ }
+ }
}
@Override
@@ -298,6 +313,12 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
mHandler.postDelayed(new PollIpSecStateRunnable(), mCancellationToken, 0L);
}
+ private boolean canStart() {
+ return mInboundTransform != null
+ && mPacketLossRatePercentThreshold
+ != IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR;
+ }
+
@Override
protected void start() {
super.start();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d20b3b22d778..f8eb78914857 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3646,7 +3646,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
// System wallpaper does not support multiple displays, attach this display to
// the fallback wallpaper.
- if (mFallbackWallpaper != null) {
+ if (mFallbackWallpaper != null && mFallbackWallpaper
+ .connection != null) {
final DisplayConnector connector = mFallbackWallpaper
.connection.getDisplayConnectorOrCreate(displayId);
if (connector == null) return;
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index c5683f31f3e7..c9395daff974 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -957,6 +957,7 @@ class ActivityClientController extends IActivityClientController.Stub {
public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) {
final long origId = Binder.clearCallingIdentity();
try {
+ ensureSetPipAspectRatioQuotaTracker();
synchronized (mGlobalLock) {
final ActivityRecord r = ensureValidPictureInPictureActivityParams(
"enterPictureInPictureMode", token, params);
@@ -971,6 +972,7 @@ class ActivityClientController extends IActivityClientController.Stub {
public void setPictureInPictureParams(IBinder token, final PictureInPictureParams params) {
final long origId = Binder.clearCallingIdentity();
try {
+ ensureSetPipAspectRatioQuotaTracker();
synchronized (mGlobalLock) {
final ActivityRecord r = ensureValidPictureInPictureActivityParams(
"setPictureInPictureParams", token, params);
@@ -1023,6 +1025,19 @@ class ActivityClientController extends IActivityClientController.Stub {
}
/**
+ * Initialize the {@link #mSetPipAspectRatioQuotaTracker} if applicable, which should happen
+ * out of {@link #mGlobalLock} to avoid deadlock (AM lock is used in QuotaTrack ctor).
+ */
+ private void ensureSetPipAspectRatioQuotaTracker() {
+ if (mSetPipAspectRatioQuotaTracker == null) {
+ mSetPipAspectRatioQuotaTracker = new CountQuotaTracker(mContext,
+ Categorizer.SINGLE_CATEGORIZER);
+ mSetPipAspectRatioQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY,
+ SET_PIP_ASPECT_RATIO_LIMIT, SET_PIP_ASPECT_RATIO_TIME_WINDOW_MS);
+ }
+ }
+
+ /**
* Checks the state of the system and the activity associated with the given {@param token} to
* verify that picture-in-picture is supported for that activity.
*
@@ -1049,12 +1064,6 @@ class ActivityClientController extends IActivityClientController.Stub {
// Rate limit how frequent an app can request aspect ratio change via
// Activity#setPictureInPictureParams
final int userId = UserHandle.getCallingUserId();
- if (mSetPipAspectRatioQuotaTracker == null) {
- mSetPipAspectRatioQuotaTracker = new CountQuotaTracker(mContext,
- Categorizer.SINGLE_CATEGORIZER);
- mSetPipAspectRatioQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY,
- SET_PIP_ASPECT_RATIO_LIMIT, SET_PIP_ASPECT_RATIO_TIME_WINDOW_MS);
- }
if (r.pictureInPictureArgs.hasSetAspectRatio()
&& params.hasSetAspectRatio()
&& !r.pictureInPictureArgs.getAspectRatio().equals(
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 0e446b8eaf8c..eb1f3b402364 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -39,6 +39,7 @@ import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONL
import static com.android.server.wm.ActivityTaskSupervisor.getApplicationLabel;
import static com.android.server.wm.PendingRemoteAnimationRegistry.TIMEOUT_MS;
import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg;
+import static com.android.window.flags.Flags.balImprovedMetrics;
import static com.android.window.flags.Flags.balImproveRealCallerVisibilityCheck;
import static com.android.window.flags.Flags.balRequireOptInByPendingIntentCreator;
import static com.android.window.flags.Flags.balRequireOptInSameUid;
@@ -805,14 +806,25 @@ public class BackgroundActivityStartController {
* or {@link #BAL_BLOCK} if the launch should be blocked
*/
BalVerdict checkBackgroundActivityStartAllowedByCaller(BalState state) {
- int callingUid = state.mCallingUid;
- int callingPid = state.mCallingPid;
- final String callingPackage = state.mCallingPackage;
- WindowProcessController callerApp = state.mCallerApp;
+ // This is used to block background activity launch even if the app is still
+ // visible to user after user clicking home button.
+
+ // Normal apps with visible app window will be allowed to start activity if app switching
+ // is allowed, or apps like live wallpaper with non app visible window will be allowed.
+ final boolean appSwitchAllowedOrFg = state.mAppSwitchState == APP_SWITCH_ALLOW
+ || state.mAppSwitchState == APP_SWITCH_FG_ONLY;
+ if (appSwitchAllowedOrFg && state.mCallingUidHasAnyVisibleWindow) {
+ return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
+ /*background*/ false, "callingUid has visible window");
+ }
+ if (mService.mActiveUids.hasNonAppVisibleWindow(state.mCallingUid)) {
+ return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW,
+ /*background*/ false, "callingUid has non-app visible window");
+ }
// don't abort for the most important UIDs
- final int callingAppId = UserHandle.getAppId(callingUid);
- if (callingUid == Process.ROOT_UID
+ final int callingAppId = UserHandle.getAppId(state.mCallingUid);
+ if (state.mCallingUid == Process.ROOT_UID
|| callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) {
return new BalVerdict(
@@ -821,7 +833,7 @@ public class BackgroundActivityStartController {
}
// Always allow home application to start activities.
- if (isHomeApp(callingUid, callingPackage)) {
+ if (isHomeApp(state.mCallingUid, state.mCallingPackage)) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ false,
"Home app");
@@ -836,67 +848,46 @@ public class BackgroundActivityStartController {
"Active ime");
}
- // This is used to block background activity launch even if the app is still
- // visible to user after user clicking home button.
- final int appSwitchState = mService.getBalAppSwitchesState();
-
- // don't abort if the callingUid has a visible window or is a persistent system process
- final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
- final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
- final boolean isCallingUidPersistentSystemProcess =
- callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-
- // Normal apps with visible app window will be allowed to start activity if app switching
- // is allowed, or apps like live wallpaper with non app visible window will be allowed.
- final boolean appSwitchAllowedOrFg =
- appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
- if (appSwitchAllowedOrFg && callingUidHasAnyVisibleWindow) {
- return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
- /*background*/ false, "callingUid has visible window");
- }
- if (mService.mActiveUids.hasNonAppVisibleWindow(callingUid)) {
- return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW,
- /*background*/ false, "callingUid has non-app visible window");
- }
-
- if (isCallingUidPersistentSystemProcess) {
+ // don't abort if the callingUid is a persistent system process
+ if (state.mIsCallingUidPersistentSystemProcess) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ false, "callingUid is persistent system process");
}
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
- if (hasBalPermission(callingUid, callingPid)) {
+ if (hasBalPermission(state.mCallingUid, state.mCallingPid)) {
return new BalVerdict(BAL_ALLOW_PERMISSION,
/*background*/ true,
"START_ACTIVITIES_FROM_BACKGROUND permission granted");
}
// don't abort if the caller has the same uid as the recents component
- if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
+ if (mSupervisor.mRecentTasks.isCallerRecents(state.mCallingUid)) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ true, "Recents Component");
}
// don't abort if the callingUid is the device owner
- if (mService.isDeviceOwner(callingUid)) {
+ if (mService.isDeviceOwner(state.mCallingUid)) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ true, "Device Owner");
}
// don't abort if the callingUid is a affiliated profile owner
- if (mService.isAffiliatedProfileOwner(callingUid)) {
+ if (mService.isAffiliatedProfileOwner(state.mCallingUid)) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ true, "Affiliated Profile Owner");
}
// don't abort if the callingUid has companion device
- final int callingUserId = UserHandle.getUserId(callingUid);
- if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
+ final int callingUserId = UserHandle.getUserId(state.mCallingUid);
+ if (mService.isAssociatedCompanionApp(callingUserId, state.mCallingUid)) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT,
/*background*/ true, "Companion App");
}
// don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
- if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
+ if (mService.hasSystemAlertWindowPermission(state.mCallingUid, state.mCallingPid,
+ state.mCallingPackage)) {
Slog.w(
TAG,
"Background activity start for "
- + callingPackage
+ + state.mCallingPackage
+ " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
return new BalVerdict(BAL_ALLOW_SAW_PERMISSION,
/*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted");
@@ -905,7 +896,7 @@ public class BackgroundActivityStartController {
// OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop
if (isSystemExemptFlagEnabled() && mService.getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
- callingUid, callingPackage) == AppOpsManager.MODE_ALLOWED) {
+ state.mCallingUid, state.mCallingPackage) == AppOpsManager.MODE_ALLOWED) {
return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true,
"OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
}
@@ -914,7 +905,7 @@ public class BackgroundActivityStartController {
// That's the case for PendingIntent-based starts, since the creator's process might not be
// up and alive.
// Don't abort if the callerApp or other processes of that uid are allowed in any way.
- BalVerdict callerAppAllowsBal = checkProcessAllowsBal(callerApp, state);
+ BalVerdict callerAppAllowsBal = checkProcessAllowsBal(state.mCallerApp, state);
if (callerAppAllowsBal.allows()) {
return callerAppAllowsBal;
}
@@ -929,13 +920,6 @@ public class BackgroundActivityStartController {
*/
BalVerdict checkBackgroundActivityStartAllowedBySender(BalState state) {
- if (state.isPendingIntentBalAllowedByPermission()
- && hasBalPermission(state.mRealCallingUid, state.mRealCallingPid)) {
- return new BalVerdict(BAL_ALLOW_PERMISSION,
- /*background*/ false,
- "realCallingUid has BAL permission.");
- }
-
// Normal apps with visible app window will be allowed to start activity if app switching
// is allowed, or apps like live wallpaper with non app visible window will be allowed.
// The home app can start apps even if app switches are usually disallowed.
@@ -961,6 +945,13 @@ public class BackgroundActivityStartController {
}
}
+ if (state.isPendingIntentBalAllowedByPermission()
+ && hasBalPermission(state.mRealCallingUid, state.mRealCallingPid)) {
+ return new BalVerdict(BAL_ALLOW_PERMISSION,
+ /*background*/ false,
+ "realCallingUid has BAL permission.");
+ }
+
// if the realCallingUid is a persistent system process, abort if the IntentSender
// wasn't allowed to start an activity
if (state.mForcedBalByPiSender.allowsBackgroundActivityStarts()
@@ -1660,26 +1651,61 @@ public class BackgroundActivityStartController {
(state.mOriginatingPendingIntent != null));
}
- @BalCode int code = finalVerdict.getCode();
- int callingUid = state.mCallingUid;
- int realCallingUid = state.mRealCallingUid;
- Intent intent = state.mIntent;
-
- if (code == BAL_ALLOW_PENDING_INTENT
- && (callingUid < Process.FIRST_APPLICATION_UID
- || realCallingUid < Process.FIRST_APPLICATION_UID)) {
- String activityName = intent != null
- ? requireNonNull(intent.getComponent()).flattenToShortString() : "";
- writeBalAllowedLog(activityName, BAL_ALLOW_PENDING_INTENT,
- state);
+ if (balImprovedMetrics()) {
+ if (shouldLogStats(finalVerdict, state)) {
+ String activityName;
+ if (shouldLogIntentActivity(finalVerdict, state)) {
+ Intent intent = state.mIntent;
+ activityName = intent == null ? "noIntent" // should never happen
+ : requireNonNull(intent.getComponent()).flattenToShortString();
+ } else {
+ activityName = "";
+ }
+ writeBalAllowedLog(activityName, finalVerdict.getCode(), state);
+ }
+ } else {
+ @BalCode int code = finalVerdict.getCode();
+ int callingUid = state.mCallingUid;
+ int realCallingUid = state.mRealCallingUid;
+ Intent intent = state.mIntent;
+
+ if (code == BAL_ALLOW_PENDING_INTENT
+ && (callingUid < Process.FIRST_APPLICATION_UID
+ || realCallingUid < Process.FIRST_APPLICATION_UID)) {
+ String activityName = intent != null
+ ? requireNonNull(intent.getComponent()).flattenToShortString() : "";
+ writeBalAllowedLog(activityName, BAL_ALLOW_PENDING_INTENT,
+ state);
+ }
+ if (code == BAL_ALLOW_PERMISSION || code == BAL_ALLOW_FOREGROUND
+ || code == BAL_ALLOW_SAW_PERMISSION) {
+ // We don't need to know which activity in this case.
+ writeBalAllowedLog("", code, state);
+ }
}
- if (code == BAL_ALLOW_PERMISSION || code == BAL_ALLOW_FOREGROUND
- || code == BAL_ALLOW_SAW_PERMISSION) {
- // We don't need to know which activity in this case.
- writeBalAllowedLog("", code, state);
+ return finalVerdict;
+ }
+ @VisibleForTesting
+ boolean shouldLogStats(BalVerdict finalVerdict, BalState state) {
+ if (finalVerdict.blocks()) {
+ return false;
}
- return finalVerdict;
+ if (!state.isPendingIntent() && finalVerdict.getRawCode() == BAL_ALLOW_VISIBLE_WINDOW) {
+ return false;
+ }
+ if (state.mBalAllowedByPiSender.allowsBackgroundActivityStarts()
+ && state.mResultForRealCaller.getRawCode() == BAL_ALLOW_VISIBLE_WINDOW) {
+ return false;
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ boolean shouldLogIntentActivity(BalVerdict finalVerdict, BalState state) {
+ return finalVerdict.mBasedOnRealCaller
+ ? state.mRealCallingUid < Process.FIRST_APPLICATION_UID
+ : state.mCallingUid < Process.FIRST_APPLICATION_UID;
}
@VisibleForTesting void writeBalAllowedLog(String activityName, int code, BalState state) {
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 1c599777e497..6aa00397fbf0 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -80,8 +80,8 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {
LaunchParamsController.LaunchParams outParams) {
if (!canEnterDesktopMode(mContext)) {
- appendLog("desktop mode is not enabled, continuing");
- return RESULT_CONTINUE;
+ appendLog("desktop mode is not enabled, skipping");
+ return RESULT_SKIP;
}
if (task == null) {
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 5aa0ed7ce76c..ce1a72deb523 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -25,7 +25,6 @@ import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Color;
import android.provider.DeviceConfig;
-import android.util.Slog;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -33,6 +32,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Function;
+import java.util.function.IntSupplier;
/** Reads letterbox configs from resources and controls their overrides at runtime. */
final class LetterboxConfiguration {
@@ -265,6 +265,12 @@ final class LetterboxConfiguration {
// unresizable apps
private boolean mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox;
+ // Supplier for the value in pixel to consider when detecting vertical thin letterboxing
+ private final IntSupplier mThinLetterboxWidthFn;
+
+ // Supplier for the value in pixel to consider when detecting horizontal thin letterboxing
+ private final IntSupplier mThinLetterboxHeightFn;
+
// Allows to enable letterboxing strategy for translucent activities ignoring flags.
private boolean mTranslucentLetterboxingOverrideEnabled;
@@ -358,6 +364,10 @@ final class LetterboxConfiguration {
R.bool.config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled);
mIsPolicyForIgnoringRequestedOrientationEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled);
+ mThinLetterboxWidthFn = () -> mContext.getResources().getDimensionPixelSize(
+ R.dimen.config_letterboxThinLetterboxWidthDp);
+ mThinLetterboxHeightFn = () -> mContext.getResources().getDimensionPixelSize(
+ R.dimen.config_letterboxThinLetterboxHeightDp);
mLetterboxConfigurationPersister = letterboxConfigurationPersister;
mLetterboxConfigurationPersister.start();
@@ -1129,6 +1139,24 @@ final class LetterboxConfiguration {
}
/**
+ * @return Width in pixel about the padding to use to understand if the letterbox for an
+ * activity is thin. If the available space has width W and the app has width w, this
+ * is the maximum value for (W - w) / 2 to be considered for a thin letterboxed app.
+ */
+ int getThinLetterboxWidthPx() {
+ return mThinLetterboxWidthFn.getAsInt();
+ }
+
+ /**
+ * @return Height in pixel about the padding to use to understand if a letterbox is thin.
+ * If the available space has height H and the app has height h, this is the maximum
+ * value for (H - h) / 2 to be considered for a thin letterboxed app.
+ */
+ int getThinLetterboxHeightPx() {
+ return mThinLetterboxHeightFn.getAsInt();
+ }
+
+ /**
* Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable
* apps.
*/
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index b38e666ea691..9e16b8abe0de 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1024,6 +1024,67 @@ final class LetterboxUiController {
return getSplitScreenAspectRatio();
}
+ /**
+ * @return {@value true} if the resulting app is letterboxed in a way defined as thin.
+ */
+ boolean isVerticalThinLetterboxed() {
+ final int thinHeight = mLetterboxConfiguration.getThinLetterboxHeightPx();
+ if (thinHeight < 0) {
+ return false;
+ }
+ final Task task = mActivityRecord.getTask();
+ if (task == null) {
+ return false;
+ }
+ final int padding = Math.abs(
+ task.getBounds().height() - mActivityRecord.getBounds().height()) / 2;
+ return padding <= thinHeight;
+ }
+
+ /**
+ * @return {@value true} if the resulting app is pillarboxed in a way defined as thin.
+ */
+ boolean isHorizontalThinLetterboxed() {
+ final int thinWidth = mLetterboxConfiguration.getThinLetterboxWidthPx();
+ if (thinWidth < 0) {
+ return false;
+ }
+ final Task task = mActivityRecord.getTask();
+ if (task == null) {
+ return false;
+ }
+ final int padding = Math.abs(
+ task.getBounds().width() - mActivityRecord.getBounds().width()) / 2;
+ return padding <= thinWidth;
+ }
+
+
+ /**
+ * @return {@value true} if the vertical reachability should be allowed in case of
+ * thin letteboxing
+ */
+ boolean allowVerticalReachabilityForThinLetterbox() {
+ if (!Flags.disableThinLetterboxingReachability()) {
+ return true;
+ }
+ // When the flag is enabled we allow vertical reachability only if the
+ // app is not thin letterboxed vertically.
+ return !isVerticalThinLetterboxed();
+ }
+
+ /**
+ * @return {@value true} if the vertical reachability should be enabled in case of
+ * thin letteboxing
+ */
+ boolean allowHorizontalReachabilityForThinLetterbox() {
+ if (!Flags.disableThinLetterboxingReachability()) {
+ return true;
+ }
+ // When the flag is enabled we allow horizontal reachability only if the
+ // app is not thin pillarboxed.
+ return !isHorizontalThinLetterboxed();
+ }
+
float getSplitScreenAspectRatio() {
// Getting the same aspect ratio that apps get in split screen.
final DisplayArea displayArea = mActivityRecord.getDisplayArea();
@@ -1263,6 +1324,9 @@ final class LetterboxUiController {
* </ul>
*/
private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) {
+ if (!allowHorizontalReachabilityForThinLetterbox()) {
+ return false;
+ }
// Use screen resolved bounds which uses resolved bounds or size compat bounds
// as activity bounds can sometimes be empty
final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior()
@@ -1298,6 +1362,9 @@ final class LetterboxUiController {
* </ul>
*/
private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) {
+ if (!allowVerticalReachabilityForThinLetterbox()) {
+ return false;
+ }
// Use screen resolved bounds which uses resolved bounds or size compat bounds
// as activity bounds can sometimes be empty
final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior()
@@ -1566,6 +1633,8 @@ final class LetterboxUiController {
if (!shouldShowLetterboxUi) {
return;
}
+ pw.println(prefix + " isVerticalThinLetterboxed=" + isVerticalThinLetterboxed());
+ pw.println(prefix + " isHorizontalThinLetterboxed=" + isHorizontalThinLetterboxed());
pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString(
getLetterboxBackgroundColor().toArgb()));
pw.println(prefix + " letterboxBackgroundType="
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index ce47f5cc8a7e..60454fc5d7c6 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -18,6 +18,7 @@ rgl@google.com
yunfanc@google.com
wilsonshih@google.com
jiamingliu@google.com
+pdwilliams@google.com
# Files related to background activity launches
per-file Background*Start* = set noparent
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 8e78d25d8373..6dec71260fa7 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -708,26 +708,6 @@ class RecentTasks {
}
}
- /**
- * Removes the oldest recent task that is compatible with the given one. This is possible if
- * the task windowing mode changed after being added to the Recents.
- */
- void removeCompatibleRecentTask(Task task) {
- final int taskIndex = mTasks.indexOf(task);
- if (taskIndex < 0) {
- return;
- }
-
- final int candidateIndex = findRemoveIndexForTask(task, false /* includingSelf */);
- if (candidateIndex == -1) {
- // Nothing to trim
- return;
- }
-
- final Task taskToRemove = taskIndex > candidateIndex ? task : mTasks.get(candidateIndex);
- remove(taskToRemove);
- }
-
void removeTasksByPackageName(String packageName, int userId) {
for (int i = mTasks.size() - 1; i >= 0; --i) {
final Task task = mTasks.get(i);
@@ -1615,10 +1595,6 @@ class RecentTasks {
* list (if any).
*/
private int findRemoveIndexForAddTask(Task task) {
- return findRemoveIndexForTask(task, true /* includingSelf */);
- }
-
- private int findRemoveIndexForTask(Task task, boolean includingSelf) {
final int recentsCount = mTasks.size();
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
@@ -1674,8 +1650,6 @@ class RecentTasks {
// existing task
continue;
}
- } else if (!includingSelf) {
- continue;
}
return i;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 5f136727008b..8bd7b5f78cf4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -20,7 +20,6 @@ import static android.app.ActivityManager.isStartResultSuccessful;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.INVALID_WINDOWING_MODE;
import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -171,7 +170,6 @@ import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.RemoteAnimationAdapter;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
@@ -362,6 +360,10 @@ class Task extends TaskFragment {
* user wants to return to it. */
private WindowProcessController mRootProcess;
+ /** The TF host info are set once the task has ever added an organized task fragment. */
+ int mTaskFragmentHostUid;
+ String mTaskFragmentHostProcessName;
+
/** Takes on same value as first root activity */
boolean isPersistable = false;
int maxRecents;
@@ -438,16 +440,6 @@ class Task extends TaskFragment {
// Id of the previous display the root task was on.
int mPrevDisplayId = INVALID_DISPLAY;
- /** ID of the display which rotation {@link #mRotation} has. */
- private int mLastRotationDisplayId = INVALID_DISPLAY;
-
- /**
- * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was
- * moved to a new display.
- */
- @Surface.Rotation
- private int mRotation;
-
int mMultiWindowRestoreWindowingMode = INVALID_WINDOWING_MODE;
/**
@@ -458,10 +450,7 @@ class Task extends TaskFragment {
*/
int mLastReportedRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- // For comparison with DisplayContent bounds.
- private Rect mTmpRect = new Rect();
- // For handling display rotations.
- private Rect mTmpRect2 = new Rect();
+ private final Rect mTmpRect = new Rect();
// Resize mode of the task. See {@link ActivityInfo#resizeMode}
// Based on the {@link ActivityInfo#resizeMode} of the root activity.
@@ -1194,9 +1183,6 @@ class Task extends TaskFragment {
updateOverrideConfigurationFromLaunchBounds();
}
- // Update task bounds if needed.
- adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
-
mRootWindowContainer.updateUIDsPresentOnDisplay();
// Ensure all animations are finished at same time in split-screen mode.
@@ -1468,6 +1454,11 @@ class Task extends TaskFragment {
// passed from Task constructor.
final TaskFragment childTaskFrag = child.asTaskFragment();
if (childTaskFrag != null && childTaskFrag.asTask() == null) {
+ if (childTaskFrag.mTaskFragmentOrganizerProcessName != null
+ && mTaskFragmentHostProcessName == null) {
+ mTaskFragmentHostUid = childTaskFrag.mTaskFragmentOrganizerUid;
+ mTaskFragmentHostProcessName = childTaskFrag.mTaskFragmentOrganizerProcessName;
+ }
childTaskFrag.setMinDimensions(mMinWidth, mMinHeight);
// The starting window should keep covering its task when a pure TaskFragment is added
@@ -2731,15 +2722,7 @@ class Task extends TaskFragment {
return setBounds(getRequestedOverrideBounds(), bounds);
}
- int rotation = Surface.ROTATION_0;
- final DisplayContent displayContent = getRootTask() != null
- ? getRootTask().getDisplayContent() : null;
- if (displayContent != null) {
- rotation = displayContent.getDisplayInfo().rotation;
- }
-
final int boundsChange = super.setBounds(bounds);
- mRotation = rotation;
updateSurfacePositionNonOrganized();
return boundsChange;
}
@@ -2799,10 +2782,6 @@ class Task extends TaskFragment {
@Override
void onDisplayChanged(DisplayContent dc) {
- final boolean isRootTask = isRootTask();
- if (!isRootTask && !mCreatedByOrganizer) {
- adjustBoundsForDisplayChangeIfNeeded(dc);
- }
super.onDisplayChanged(dc);
if (isLeafTask()) {
final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
@@ -2953,48 +2932,6 @@ class Task extends TaskFragment {
return mDragResizing;
}
- void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
- if (displayContent == null) {
- return;
- }
- if (getRequestedOverrideBounds().isEmpty()) {
- return;
- }
- final int displayId = displayContent.getDisplayId();
- final int newRotation = displayContent.getDisplayInfo().rotation;
- if (displayId != mLastRotationDisplayId) {
- // This task is on a display that it wasn't on. There is no point to keep the relative
- // position if display rotations for old and new displays are different. Just keep these
- // values.
- mLastRotationDisplayId = displayId;
- mRotation = newRotation;
- return;
- }
-
- if (mRotation == newRotation) {
- // Rotation didn't change. We don't need to adjust the bounds to keep the relative
- // position.
- return;
- }
-
- // Device rotation changed.
- // - We don't want the task to move around on the screen when this happens, so update the
- // task bounds so it stays in the same place.
- // - Rotate the bounds and notify activity manager if the task can be resized independently
- // from its root task. The root task will take care of task rotation for the other case.
- mTmpRect2.set(getBounds());
-
- if (!getWindowConfiguration().canResizeTask()) {
- setBounds(mTmpRect2);
- return;
- }
-
- displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
- if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
- mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
- }
- }
-
/** Cancels any running app transitions associated with the task. */
void cancelTaskWindowTransition() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
@@ -3525,8 +3462,6 @@ class Task extends TaskFragment {
info.isVisibleRequested = isVisibleRequested();
info.isSleeping = shouldSleepActivities();
info.isTopActivityTransparent = top != null && !top.fillsParent();
- appCompatTaskInfo.isLetterboxDoubleTapEnabled = top != null
- && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled();
appCompatTaskInfo.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
appCompatTaskInfo.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
@@ -3541,15 +3476,29 @@ class Task extends TaskFragment {
appCompatTaskInfo.topActivityLetterboxWidth = top.getBounds().width();
appCompatTaskInfo.topActivityLetterboxHeight = top.getBounds().height();
}
+ // We need to consider if letterboxed or pillarboxed
+ // TODO(b/336807329) Encapsulate reachability logic
+ appCompatTaskInfo.isLetterboxDoubleTapEnabled = top != null
+ && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled();
if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) {
if (appCompatTaskInfo.isTopActivityPillarboxed()) {
- // Pillarboxed
- appCompatTaskInfo.topActivityLetterboxHorizontalPosition =
- top.mLetterboxUiController.getLetterboxPositionForHorizontalReachability();
+ if (top.mLetterboxUiController.allowHorizontalReachabilityForThinLetterbox()) {
+ // Pillarboxed
+ appCompatTaskInfo.topActivityLetterboxHorizontalPosition =
+ top.mLetterboxUiController
+ .getLetterboxPositionForHorizontalReachability();
+ } else {
+ appCompatTaskInfo.isLetterboxDoubleTapEnabled = false;
+ }
} else {
- // Letterboxed
- appCompatTaskInfo.topActivityLetterboxVerticalPosition =
- top.mLetterboxUiController.getLetterboxPositionForVerticalReachability();
+ if (top.mLetterboxUiController.allowVerticalReachabilityForThinLetterbox()) {
+ // Letterboxed
+ appCompatTaskInfo.topActivityLetterboxVerticalPosition =
+ top.mLetterboxUiController
+ .getLetterboxPositionForVerticalReachability();
+ } else {
+ appCompatTaskInfo.isLetterboxDoubleTapEnabled = false;
+ }
}
}
appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton = top != null
@@ -6888,7 +6837,7 @@ class Task extends TaskFragment {
mIsBoosted = isBoosted;
// The client transaction will be applied together with the next assignLayer.
if (clientTransaction != null) {
- mDecorSurfaceContainer.mPendingClientTransactions.add(clientTransaction);
+ mPendingClientTransactions.add(clientTransaction);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 2b631f7a404e..6a7f60b3447d 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -320,9 +320,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
/** Organizer that organizing this TaskFragment. */
@Nullable
private ITaskFragmentOrganizer mTaskFragmentOrganizer;
- @VisibleForTesting
+
int mTaskFragmentOrganizerUid = INVALID_UID;
- private @Nullable String mTaskFragmentOrganizerProcessName;
+ @Nullable String mTaskFragmentOrganizerProcessName;
/** Client assigned unique token for this TaskFragment if this is created by an organizer. */
@Nullable
@@ -485,14 +485,16 @@ class TaskFragment extends WindowContainer<WindowContainer> {
*/
@Nullable
private WindowProcessController getOrganizerProcessIfDifferent(@Nullable ActivityRecord r) {
- if ((r == null || mTaskFragmentOrganizerProcessName == null)
- || (mTaskFragmentOrganizerProcessName.equals(r.processName)
- && mTaskFragmentOrganizerUid == r.getUid())) {
- // No organizer or the process is the same.
+ final Task task = getTask();
+ if (r == null || task == null || task.mTaskFragmentHostProcessName == null) {
+ return null;
+ }
+ if (task.mTaskFragmentHostProcessName.equals(r.processName)
+ && task.mTaskFragmentHostUid == r.getUid()) {
return null;
}
- return mAtmService.getProcessController(mTaskFragmentOrganizerProcessName,
- mTaskFragmentOrganizerUid);
+ return mAtmService.getProcessController(task.mTaskFragmentHostProcessName,
+ task.mTaskFragmentHostUid);
}
void setAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 1573d09364ea..90e7bd7b99e6 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1916,7 +1916,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final int count = tasksToReparent.size();
for (int i = 0; i < count; ++i) {
final Task task = tasksToReparent.get(i);
- final int prevWindowingMode = task.getWindowingMode();
if (syncId >= 0) {
addToSyncSet(syncId, task);
}
@@ -1930,12 +1929,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
false /*moveParents*/, "processChildrenTaskReparentHierarchyOp");
}
- // Trim the compatible Recent task (if any) after the Task is reparented and now has
- // a different windowing mode, in order to prevent redundant Recent tasks after
- // reparenting.
- if (prevWindowingMode != task.getWindowingMode()) {
- mService.mTaskSupervisor.mRecentTasks.removeCompatibleRecentTask(task);
- }
}
if (transition != null) transition.collect(newParent);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c25080f9e756..e90c845f0d21 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -858,6 +858,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* {@link InsetsStateController#notifyInsetsChanged}.
*/
boolean isReadyToDispatchInsetsState() {
+ if (mStartingData != null) {
+ // Starting window doesn't consider insets.
+ return false;
+ }
final boolean visible = shouldCheckTokenVisibleRequested()
? isVisibleRequested() : isVisible();
return visible && mFrozenInsetsState == null;
diff --git a/services/core/jni/com_android_server_hint_HintManagerService.cpp b/services/core/jni/com_android_server_hint_HintManagerService.cpp
index be188358b90b..2307aced6141 100644
--- a/services/core/jni/com_android_server_hint_HintManagerService.cpp
+++ b/services/core/jni/com_android_server_hint_HintManagerService.cpp
@@ -34,11 +34,8 @@
#include "jni.h"
-using aidl::android::hardware::power::SessionConfig;
-using aidl::android::hardware::power::SessionHint;
-using aidl::android::hardware::power::SessionMode;
-using aidl::android::hardware::power::SessionTag;
-using aidl::android::hardware::power::WorkDuration;
+namespace hal = aidl::android::hardware::power;
+
using android::power::PowerHintSessionWrapper;
namespace android {
@@ -95,10 +92,11 @@ static jlong createHintSession(JNIEnv* env, int32_t tgid, int32_t uid,
static jlong createHintSessionWithConfig(JNIEnv* env, int32_t tgid, int32_t uid,
std::vector<int32_t> threadIds, int64_t durationNanos,
- int32_t sessionTag, SessionConfig& config) {
+ int32_t sessionTag, hal::SessionConfig& config) {
auto result =
gPowerHalController.createHintSessionWithConfig(tgid, uid, threadIds, durationNanos,
- static_cast<SessionTag>(sessionTag),
+ static_cast<hal::SessionTag>(
+ sessionTag),
&config);
if (result.isOk()) {
jlong session_ptr = reinterpret_cast<jlong>(result.value().get());
@@ -140,12 +138,12 @@ static void updateTargetWorkDuration(int64_t session_ptr, int64_t targetDuration
}
static void reportActualWorkDuration(int64_t session_ptr,
- const std::vector<WorkDuration>& actualDurations) {
+ const std::vector<hal::WorkDuration>& actualDurations) {
auto appSession = reinterpret_cast<PowerHintSessionWrapper*>(session_ptr);
appSession->reportActualWorkDuration(actualDurations);
}
-static void sendHint(int64_t session_ptr, SessionHint hint) {
+static void sendHint(int64_t session_ptr, hal::SessionHint hint) {
auto appSession = reinterpret_cast<PowerHintSessionWrapper*>(session_ptr);
appSession->sendHint(hint);
}
@@ -155,7 +153,7 @@ static void setThreads(int64_t session_ptr, const std::vector<int32_t>& threadId
appSession->setThreads(threadIds);
}
-static void setMode(int64_t session_ptr, SessionMode mode, bool enabled) {
+static void setMode(int64_t session_ptr, hal::SessionMode mode, bool enabled) {
auto appSession = reinterpret_cast<PowerHintSessionWrapper*>(session_ptr);
appSession->setMode(mode, enabled);
}
@@ -189,7 +187,7 @@ static jlong nativeCreateHintSessionWithConfig(JNIEnv* env, jclass /* clazz */,
return 0;
}
std::vector<int32_t> threadIds(tidArray.get(), tidArray.get() + tidArray.size());
- SessionConfig config;
+ hal::SessionConfig config;
jlong out = createHintSessionWithConfig(env, tgid, uid, std::move(threadIds), durationNanos,
sessionTag, config);
if (out <= 0) {
@@ -223,7 +221,7 @@ static void nativeReportActualWorkDuration(JNIEnv* env, jclass /* clazz */, jlon
ScopedLongArrayRO arrayActualDurations(env, actualDurations);
ScopedLongArrayRO arrayTimeStamps(env, timeStamps);
- std::vector<WorkDuration> actualList(arrayActualDurations.size());
+ std::vector<hal::WorkDuration> actualList(arrayActualDurations.size());
for (size_t i = 0; i < arrayActualDurations.size(); i++) {
actualList[i].timeStampNanos = arrayTimeStamps[i];
actualList[i].durationNanos = arrayActualDurations[i];
@@ -232,7 +230,7 @@ static void nativeReportActualWorkDuration(JNIEnv* env, jclass /* clazz */, jlon
}
static void nativeSendHint(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jint hint) {
- sendHint(session_ptr, static_cast<SessionHint>(hint));
+ sendHint(session_ptr, static_cast<hal::SessionHint>(hint));
}
static void nativeSetThreads(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jintArray tids) {
@@ -244,13 +242,13 @@ static void nativeSetThreads(JNIEnv* env, jclass /* clazz */, jlong session_ptr,
static void nativeSetMode(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jint mode,
jboolean enabled) {
- setMode(session_ptr, static_cast<SessionMode>(mode), enabled);
+ setMode(session_ptr, static_cast<hal::SessionMode>(mode), enabled);
}
static void nativeReportActualWorkDuration2(JNIEnv* env, jclass /* clazz */, jlong session_ptr,
jobjectArray jWorkDurations) {
int size = env->GetArrayLength(jWorkDurations);
- std::vector<WorkDuration> workDurations(size);
+ std::vector<hal::WorkDuration> workDurations(size);
for (int i = 0; i < size; i++) {
jobject workDuration = env->GetObjectArrayElement(jWorkDurations, i);
workDurations[i].workPeriodStartTimestampNanos =
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 32cb2510bc9f..fac08eb78726 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -88,7 +88,6 @@ namespace input_flags = com::android::input::flags;
namespace android {
-static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
static const bool ENABLE_INPUT_FILTER_RUST = input_flags::enable_input_filter_rust_impl();
// The exponent used to calculate the pointer speed scaling factor.
@@ -298,10 +297,8 @@ public:
void setShowTouches(bool enabled);
void setInteractive(bool interactive);
void reloadCalibration();
- void setPointerIconType(PointerIconStyle iconId);
void reloadPointerIcons();
void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled);
- void setCustomPointerIcon(const SpriteIcon& icon);
bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
int32_t displayId, DeviceId deviceId, int32_t pointerId,
const sp<IBinder>& inputToken);
@@ -316,7 +313,6 @@ public:
/* --- InputReaderPolicyInterface implementation --- */
void getReaderConfiguration(InputReaderConfiguration* outConfig) override;
- std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override;
void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override;
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier,
@@ -375,7 +371,6 @@ public:
virtual PointerIconStyle getDefaultPointerIconId();
virtual PointerIconStyle getDefaultStylusIconId();
virtual PointerIconStyle getCustomPointerIconId();
- virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position);
/* --- PointerChoreographerPolicyInterface implementation --- */
std::shared_ptr<PointerControllerInterface> createPointerController(
@@ -409,19 +404,12 @@ private:
// True if pointer gestures are enabled.
bool pointerGesturesEnabled{true};
- // Show touches feature enable/disable.
- bool showTouches{false};
-
// The latest request to enable or disable Pointer Capture.
PointerCaptureRequest pointerCaptureRequest{};
// Sprite controller singleton, created on first use.
std::shared_ptr<SpriteController> spriteController{};
- // TODO(b/293587049): Remove when the PointerChoreographer refactoring is complete.
- // Pointer controller singleton, created and destroyed as needed.
- std::weak_ptr<PointerController> legacyPointerController{};
-
// The list of PointerControllers created and managed by the PointerChoreographer.
std::list<std::weak_ptr<PointerController>> pointerControllers{};
@@ -504,14 +492,10 @@ void NativeInputManager::dump(std::string& dump) {
dump += StringPrintf(INDENT "Display with Mouse Pointer Acceleration Disabled: %s\n",
dumpSet(mLocked.displaysWithMousePointerAccelerationDisabled).c_str());
dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n",
- toString(mLocked.pointerGesturesEnabled));
- dump += StringPrintf(INDENT "Show Touches: %s\n", toString(mLocked.showTouches));
+ toString(mLocked.pointerGesturesEnabled));
dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
mLocked.pointerCaptureRequest.isEnable() ? "Enabled" : "Disabled",
mLocked.pointerCaptureRequest.seq);
- if (auto pc = mLocked.legacyPointerController.lock(); pc) {
- dump += pc->dump();
- }
} // release lock
dump += "\n";
@@ -556,9 +540,7 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO
[&viewports](PointerController& pc) { pc.onDisplayViewportsUpdated(viewports); });
} // release lock
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- mInputManager->getChoreographer().setDisplayViewports(viewports);
- }
+ mInputManager->getChoreographer().setDisplayViewports(viewports);
mInputManager->getReader().requestRefreshConfiguration(
InputReaderConfiguration::Change::DISPLAY_INFO);
}
@@ -700,8 +682,6 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
: 1;
outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;
- outConfig->showTouches = mLocked.showTouches;
-
outConfig->pointerCaptureRequest = mLocked.pointerCaptureRequest;
outConfig->setDisplayViewports(mLocked.viewports);
@@ -743,10 +723,6 @@ std::unordered_map<std::string, T> NativeInputManager::readMapFromInterleavedJav
void NativeInputManager::forEachPointerControllerLocked(
std::function<void(PointerController&)> apply) {
- if (auto pc = mLocked.legacyPointerController.lock(); pc) {
- apply(*pc);
- }
-
auto it = mLocked.pointerControllers.begin();
while (it != mLocked.pointerControllers.end()) {
auto pc = it->lock();
@@ -780,50 +756,16 @@ PointerIcon NativeInputManager::loadPointerIcon(JNIEnv* env, int32_t displayId,
return android_view_PointerIcon_toNative(env, pointerIconObj.get());
}
-// TODO(b/293587049): Remove the old way of obtaining PointerController when the
-// PointerChoreographer refactoring is complete.
-std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerController(
- int32_t /* deviceId */) {
- ATRACE_CALL();
- std::scoped_lock _l(mLock);
-
- std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
- if (controller == nullptr) {
- ensureSpriteControllerLocked();
-
- // Disable the functionality of the legacy PointerController if PointerChoreographer is
- // enabled.
- controller = PointerController::create(this, mLooper, *mLocked.spriteController,
- /*enabled=*/!ENABLE_POINTER_CHOREOGRAPHER);
- mLocked.legacyPointerController = controller;
- updateInactivityTimeoutLocked();
- }
-
- return controller;
-}
-
std::shared_ptr<PointerControllerInterface> NativeInputManager::createPointerController(
PointerControllerInterface::ControllerType type) {
std::scoped_lock _l(mLock);
ensureSpriteControllerLocked();
std::shared_ptr<PointerController> pc =
- PointerController::create(this, mLooper, *mLocked.spriteController, /*enabled=*/true,
- type);
+ PointerController::create(this, mLooper, *mLocked.spriteController, type);
mLocked.pointerControllers.emplace_back(pc);
return pc;
}
-void NativeInputManager::onPointerDisplayIdChanged(int32_t pointerDisplayId,
- const FloatPoint& position) {
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- return;
- }
- JNIEnv* env = jniEnv();
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.onPointerDisplayIdChanged, pointerDisplayId,
- position.x, position.y);
- checkAndClearExceptionFromCallback(env, "onPointerDisplayIdChanged");
-}
-
void NativeInputManager::notifyPointerDisplayIdChanged(int32_t pointerDisplayId,
const FloatPoint& position) {
// Notify the Reader so that devices can be reconfigured.
@@ -1210,23 +1152,7 @@ void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
}
void NativeInputManager::setPointerDisplayId(int32_t displayId) {
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- mInputManager->getChoreographer().setDefaultMouseDisplayId(displayId);
- } else {
- { // acquire lock
- std::scoped_lock _l(mLock);
-
- if (mLocked.pointerDisplayId == displayId) {
- return;
- }
-
- ALOGI("Setting pointer display id to %d.", displayId);
- mLocked.pointerDisplayId = displayId;
- } // release lock
-
- mInputManager->getReader().requestRefreshConfiguration(
- InputReaderConfiguration::Change::DISPLAY_INFO);
- }
+ mInputManager->getChoreographer().setDefaultMouseDisplayId(displayId);
}
int32_t NativeInputManager::getMousePointerSpeed() {
@@ -1378,24 +1304,7 @@ void NativeInputManager::setInputDeviceEnabled(uint32_t deviceId, bool enabled)
}
void NativeInputManager::setShowTouches(bool enabled) {
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- mInputManager->getChoreographer().setShowTouchesEnabled(enabled);
- return;
- }
-
- { // acquire lock
- std::scoped_lock _l(mLock);
-
- if (mLocked.showTouches == enabled) {
- return;
- }
-
- ALOGI("Setting show touches feature to %s.", enabled ? "enabled" : "disabled");
- mLocked.showTouches = enabled;
- } // release lock
-
- mInputManager->getReader().requestRefreshConfiguration(
- InputReaderConfiguration::Change::SHOW_TOUCHES);
+ mInputManager->getChoreographer().setShowTouchesEnabled(enabled);
}
void NativeInputManager::requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) {
@@ -1411,27 +1320,11 @@ void NativeInputManager::reloadCalibration() {
InputReaderConfiguration::Change::TOUCH_AFFINE_TRANSFORMATION);
}
-void NativeInputManager::setPointerIconType(PointerIconStyle iconId) {
- std::scoped_lock _l(mLock);
- std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
- if (controller != nullptr) {
- controller->updatePointerIcon(iconId);
- }
-}
-
void NativeInputManager::reloadPointerIcons() {
std::scoped_lock _l(mLock);
forEachPointerControllerLocked([](PointerController& pc) { pc.reloadPointerResources(); });
}
-void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) {
- std::scoped_lock _l(mLock);
- std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
- if (controller != nullptr) {
- controller->setCustomPointerIcon(icon);
- }
-}
-
bool NativeInputManager::setPointerIcon(
std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId,
DeviceId deviceId, int32_t pointerId, const sp<IBinder>& inputToken) {
@@ -1447,9 +1340,6 @@ bool NativeInputManager::setPointerIcon(
}
void NativeInputManager::setPointerIconVisibility(int32_t displayId, bool visible) {
- if (!ENABLE_POINTER_CHOREOGRAPHER) {
- return;
- }
mInputManager->getChoreographer().setPointerIconVisibility(displayId, visible);
}
@@ -1819,36 +1709,12 @@ void NativeInputManager::setStylusButtonMotionEventsEnabled(bool enabled) {
}
FloatPoint NativeInputManager::getMouseCursorPosition(int32_t displayId) {
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- return mInputManager->getChoreographer().getMouseCursorPosition(displayId);
- }
- // To maintain the status-quo, the displayId parameter (used when PointerChoreographer is
- // enabled) is ignored in the old pipeline.
- std::scoped_lock _l(mLock);
- const auto pc = mLocked.legacyPointerController.lock();
- if (!pc) return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
-
- return pc->getPosition();
+ return mInputManager->getChoreographer().getMouseCursorPosition(displayId);
}
void NativeInputManager::setStylusPointerIconEnabled(bool enabled) {
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- mInputManager->getChoreographer().setStylusPointerIconEnabled(enabled);
- return;
- }
-
- { // acquire lock
- std::scoped_lock _l(mLock);
-
- if (mLocked.stylusPointerIconEnabled == enabled) {
- return;
- }
-
- mLocked.stylusPointerIconEnabled = enabled;
- } // release lock
-
- mInputManager->getReader().requestRefreshConfiguration(
- InputReaderConfiguration::Change::DISPLAY_INFO);
+ mInputManager->getChoreographer().setStylusPointerIconEnabled(enabled);
+ return;
}
void NativeInputManager::setInputMethodConnectionIsActive(bool isActive) {
@@ -2598,13 +2464,7 @@ static void nativeDisableInputDevice(JNIEnv* env, jobject nativeImplObj, jint de
}
static void nativeSetPointerIconType(JNIEnv* env, jobject nativeImplObj, jint iconId) {
- // iconId is set in java from from frameworks/base/core/java/android/view/PointerIcon.java,
- // where the definition in <input/Input.h> is duplicated as a sealed class (type safe enum
- // equivalent in Java).
-
- NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
-
- im->setPointerIconType(static_cast<PointerIconStyle>(iconId));
+ // TODO(b/311416205): Remove
}
static void nativeReloadPointerIcons(JNIEnv* env, jobject nativeImplObj) {
@@ -2614,8 +2474,7 @@ static void nativeReloadPointerIcons(JNIEnv* env, jobject nativeImplObj) {
}
static void nativeSetCustomPointerIcon(JNIEnv* env, jobject nativeImplObj, jobject iconObj) {
- NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->setCustomPointerIcon(toSpriteIcon(android_view_PointerIcon_toNative(env, iconObj)));
+ // TODO(b/311416205): Remove
}
static bool nativeSetPointerIcon(JNIEnv* env, jobject nativeImplObj, jobject iconObj,
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 6ef14366b9e7..0c83e8e468d9 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -66,6 +66,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ApiStatus;
@@ -1166,11 +1167,17 @@ public final class CredentialManagerService
settingsWrapper.getStringForUser(
Settings.Secure.AUTOFILL_SERVICE, UserHandle.myUserId());
- // If there is an autofill provider and it is the placeholder indicating
+ // If there is an autofill provider and it is the credential autofill service indicating
// that the currently selected primary provider does not support autofill
- // then we should wipe the setting to keep it in sync.
- if (autofillProvider != null && primaryProviders.isEmpty()) {
- if (autofillProvider.equals(AUTOFILL_PLACEHOLDER_VALUE)) {
+ // then we should keep as is
+ String credentialAutofillService = settingsWrapper.mContext.getResources().getString(
+ R.string.config_defaultCredentialManagerAutofillService);
+ if (autofillProvider != null && primaryProviders.isEmpty() && !TextUtils.equals(
+ autofillProvider, credentialAutofillService)) {
+ // If the existing autofill provider is from the app being removed
+ // then erase the autofill service setting.
+ ComponentName cn = ComponentName.unflattenFromString(autofillProvider);
+ if (cn != null && cn.getPackageName().equals(packageName)) {
if (!settingsWrapper.putStringForUser(
Settings.Secure.AUTOFILL_SERVICE,
"",
@@ -1178,19 +1185,6 @@ public final class CredentialManagerService
/* overrideableByRestore= */ true)) {
Slog.e(TAG, "Failed to remove autofill package: " + packageName);
}
- } else {
- // If the existing autofill provider is from the app being removed
- // then erase the autofill service setting.
- ComponentName cn = ComponentName.unflattenFromString(autofillProvider);
- if (cn != null && cn.getPackageName().equals(packageName)) {
- if (!settingsWrapper.putStringForUser(
- Settings.Secure.AUTOFILL_SERVICE,
- "",
- UserHandle.myUserId(),
- /* overrideableByRestore= */ true)) {
- Slog.e(TAG, "Failed to remove autofill package: " + packageName);
- }
- }
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java
index 950ec77f5ba8..502607be7310 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java
@@ -19,7 +19,6 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.BooleanPolicyValue;
-import android.app.admin.PolicyKey;
import android.util.Log;
import com.android.modules.utils.TypedXmlPullParser;
@@ -37,8 +36,7 @@ final class BooleanPolicySerializer extends PolicySerializer<Boolean> {
private static final String TAG = "BooleanPolicySerializer";
@Override
- void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull Boolean value)
- throws IOException {
+ void saveToXml(TypedXmlSerializer serializer, @NonNull Boolean value) throws IOException {
Objects.requireNonNull(value);
serializer.attributeBoolean(/* namespace= */ null, ATTR_VALUE, value);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
index d24afabe95a4..a65c7e1870f3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
@@ -18,8 +18,6 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.app.admin.BundlePolicyValue;
-import android.app.admin.PackagePolicyKey;
-import android.app.admin.PolicyKey;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
@@ -53,14 +51,8 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> {
private static final String ATTR_TYPE_BUNDLE_ARRAY = "BA";
@Override
- void saveToXml(@NonNull PolicyKey policyKey, TypedXmlSerializer serializer,
- @NonNull Bundle value) throws IOException {
+ void saveToXml(TypedXmlSerializer serializer, @NonNull Bundle value) throws IOException {
Objects.requireNonNull(value);
- Objects.requireNonNull(policyKey);
- if (!(policyKey instanceof PackagePolicyKey)) {
- throw new IllegalArgumentException("policyKey is not of type "
- + "PackagePolicyKey");
- }
writeBundle(value, serializer);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java
index 6303a1a8b860..01f56e07e157 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java
@@ -19,7 +19,6 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.ComponentNamePolicyValue;
-import android.app.admin.PolicyKey;
import android.content.ComponentName;
import android.util.Log;
@@ -37,8 +36,7 @@ final class ComponentNamePolicySerializer extends PolicySerializer<ComponentName
private static final String ATTR_CLASS_NAME = "class-name";
@Override
- void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer,
- @NonNull ComponentName value) throws IOException {
+ void saveToXml(TypedXmlSerializer serializer, @NonNull ComponentName value) throws IOException {
Objects.requireNonNull(value);
serializer.attribute(
/* namespace= */ null, ATTR_PACKAGE_NAME, value.getPackageName());
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f553a5ad1db2..375fc5a0280a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -349,8 +349,8 @@ import android.app.admin.PolicyValue;
import android.app.admin.PreferentialNetworkServiceConfig;
import android.app.admin.SecurityLog;
import android.app.admin.SecurityLog.SecurityEvent;
+import android.app.admin.PackageSetPolicyValue;
import android.app.admin.StartInstallingUpdateCallback;
-import android.app.admin.StringSetPolicyValue;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.UnsafeStateException;
@@ -1985,11 +1985,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
CryptoTestHelper.runAndLogSelfTest();
}
- public String[] getPersonalAppsForSuspension(@UserIdInt int userId) {
- return PersonalAppsSuspensionHelper.forUser(mContext, userId)
- .getPersonalAppsForSuspension();
- }
-
public long systemCurrentTimeMillis() {
return System.currentTimeMillis();
}
@@ -12078,7 +12073,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.PERMITTED_INPUT_METHODS,
admin,
- new StringSetPolicyValue(new HashSet<>(packageList)),
+ new PackageSetPolicyValue(new HashSet<>(packageList)),
userId);
}
}
@@ -20363,12 +20358,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mDevicePolicyEngine.setGlobalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
enforcingAdmin,
- new StringSetPolicyValue(packages));
+ new PackageSetPolicyValue(packages));
} else {
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
enforcingAdmin,
- new StringSetPolicyValue(packages),
+ new PackageSetPolicyValue(packages),
caller.getUserId());
}
}
@@ -21610,9 +21605,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
== HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
}
- if (Flags.headlessSingleUserFixes() && mInjector.userManagerIsHeadlessSystemUserMode()
- && isSingleUserMode && !mInjector.isChangeEnabled(
- PROVISION_SINGLE_USER_MODE, deviceAdmin.getPackageName(), caller.getUserId())) {
+ if (Flags.headlessSingleMinTargetSdk()
+ && mInjector.userManagerIsHeadlessSystemUserMode()
+ && isSingleUserMode
+ && !mInjector.isChangeEnabled(
+ PROVISION_SINGLE_USER_MODE, deviceAdmin.getPackageName(),
+ caller.getUserId())) {
throw new IllegalStateException("Device admin is not targeting Android V.");
}
@@ -24047,7 +24045,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.PERMITTED_INPUT_METHODS,
enforcingAdmin,
- new StringSetPolicyValue(
+ new PackageSetPolicyValue(
new HashSet<>(admin.permittedInputMethods)),
admin.getUserHandle().getIdentifier());
}
@@ -24056,7 +24054,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.PERMITTED_INPUT_METHODS,
enforcingAdmin,
- new StringSetPolicyValue(
+ new PackageSetPolicyValue(
new HashSet<>(admin.getParentActiveAdmin()
.permittedInputMethods)),
getProfileParentId(admin.getUserHandle().getIdentifier()));
@@ -24112,12 +24110,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mDevicePolicyEngine.setGlobalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
enforcingAdmin,
- new StringSetPolicyValue(new HashSet<>(admin.protectedPackages)));
+ new PackageSetPolicyValue(
+ new HashSet<>(admin.protectedPackages)));
} else {
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
enforcingAdmin,
- new StringSetPolicyValue(new HashSet<>(admin.protectedPackages)),
+ new PackageSetPolicyValue(
+ new HashSet<>(admin.protectedPackages)),
admin.getUserHandle().getIdentifier());
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java
index 45a2d2a7bda1..ebbf22cfef69 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java
@@ -19,7 +19,6 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.IntegerPolicyValue;
-import android.app.admin.PolicyKey;
import android.util.Log;
import com.android.modules.utils.TypedXmlPullParser;
@@ -37,8 +36,7 @@ final class IntegerPolicySerializer extends PolicySerializer<Integer> {
private static final String ATTR_VALUE = "value";
@Override
- void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer,
- @NonNull Integer value) throws IOException {
+ void saveToXml(TypedXmlSerializer serializer, @NonNull Integer value) throws IOException {
Objects.requireNonNull(value);
serializer.attributeInt(/* namespace= */ null, ATTR_VALUE, value);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java
index 20bd2d75f846..13412d05aba3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java
@@ -18,7 +18,6 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.app.admin.LockTaskPolicy;
-import android.app.admin.PolicyKey;
import android.util.Log;
import com.android.modules.utils.TypedXmlPullParser;
@@ -39,8 +38,8 @@ final class LockTaskPolicySerializer extends PolicySerializer<LockTaskPolicy> {
private static final String ATTR_FLAGS = "flags";
@Override
- void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer,
- @NonNull LockTaskPolicy value) throws IOException {
+ void saveToXml(TypedXmlSerializer serializer, @NonNull LockTaskPolicy value)
+ throws IOException {
Objects.requireNonNull(value);
serializer.attribute(
/* namespace= */ null,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java
index 522c4b5e84be..c363e6626de3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java
@@ -19,7 +19,6 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.LongPolicyValue;
-import android.app.admin.PolicyKey;
import android.util.Log;
import com.android.modules.utils.TypedXmlPullParser;
@@ -37,8 +36,7 @@ final class LongPolicySerializer extends PolicySerializer<Long> {
private static final String ATTR_VALUE = "value";
@Override
- void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer,
- @NonNull Long value) throws IOException {
+ void saveToXml(TypedXmlSerializer serializer, @NonNull Long value) throws IOException {
Objects.requireNonNull(value);
serializer.attributeLong(/* namespace= */ null, ATTR_VALUE, value);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/StringSetPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/PackageSetPolicySerializer.java
index 0265453eecc7..c4da029c6315 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/StringSetPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PackageSetPolicySerializer.java
@@ -18,9 +18,8 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.PolicyKey;
import android.app.admin.PolicyValue;
-import android.app.admin.StringSetPolicyValue;
+import android.app.admin.PackageSetPolicyValue;
import android.util.Log;
import com.android.modules.utils.TypedXmlPullParser;
@@ -31,12 +30,11 @@ import java.util.Objects;
import java.util.Set;
// TODO(scottjonathan): Replace with generic set implementation
-final class StringSetPolicySerializer extends PolicySerializer<Set<String>> {
+final class PackageSetPolicySerializer extends PolicySerializer<Set<String>> {
private static final String ATTR_VALUES = "strings";
private static final String ATTR_VALUES_SEPARATOR = ";";
@Override
- void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer,
- @NonNull Set<String> value) throws IOException {
+ void saveToXml(TypedXmlSerializer serializer, @NonNull Set<String> value) throws IOException {
Objects.requireNonNull(value);
serializer.attribute(
/* namespace= */ null, ATTR_VALUES, String.join(ATTR_VALUES_SEPARATOR, value));
@@ -47,10 +45,10 @@ final class StringSetPolicySerializer extends PolicySerializer<Set<String>> {
PolicyValue<Set<String>> readFromXml(TypedXmlPullParser parser) {
String valuesStr = parser.getAttributeValue(/* namespace= */ null, ATTR_VALUES);
if (valuesStr == null) {
- Log.e(DevicePolicyEngine.TAG, "Error parsing StringSet policy value.");
+ Log.e(DevicePolicyEngine.TAG, "Error parsing PackageSet policy value.");
return null;
}
Set<String> values = Set.of(valuesStr.split(ATTR_VALUES_SEPARATOR));
- return new StringSetPolicyValue(values);
+ return new PackageSetPolicyValue(values);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/StringSetUnion.java b/services/devicepolicy/java/com/android/server/devicepolicy/PackageSetUnion.java
index 5298960892a3..d1e241b365a6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/StringSetUnion.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PackageSetUnion.java
@@ -18,14 +18,15 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.app.admin.PolicyValue;
-import android.app.admin.StringSetPolicyValue;
+import android.app.admin.PackageSetPolicyValue;
+import android.app.admin.StringSetUnion;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Objects;
import java.util.Set;
-final class StringSetUnion extends ResolutionMechanism<Set<String>> {
+final class PackageSetUnion extends ResolutionMechanism<Set<String>> {
@Override
PolicyValue<Set<String>> resolve(
@@ -38,17 +39,17 @@ final class StringSetUnion extends ResolutionMechanism<Set<String>> {
for (PolicyValue<Set<String>> policy : adminPolicies.values()) {
unionOfPolicies.addAll(policy.getValue());
}
- return new StringSetPolicyValue(unionOfPolicies);
+ return new PackageSetPolicyValue(unionOfPolicies);
}
@Override
- android.app.admin.StringSetUnion getParcelableResolutionMechanism() {
- return new android.app.admin.StringSetUnion();
+ StringSetUnion getParcelableResolutionMechanism() {
+ return new StringSetUnion();
}
@Override
public String toString() {
- return "SetUnion {}";
+ return "PackageSetUnion {}";
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index 8cb511e8727c..7483b43baf13 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -37,7 +37,6 @@ import android.provider.Telephony;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
-import android.util.Log;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.inputmethod.InputMethodInfo;
@@ -107,10 +106,6 @@ public final class PersonalAppsSuspensionHelper {
for (final String pkg : unsuspendablePackages) {
result.remove(pkg);
}
-
- if (Log.isLoggable(LOG_TAG, Log.INFO)) {
- Slogf.i(LOG_TAG, "Packages subject to suspension: %s", String.join(",", result));
- }
return result.toArray(new String[0]);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 7a9fa0fb5658..8d980b5031e2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -162,9 +162,9 @@ final class PolicyDefinition<V> {
new PolicyDefinition<>(
new NoArgsPolicyKey(
DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY),
- new StringSetUnion(),
+ new PackageSetUnion(),
PolicyEnforcerCallbacks::setUserControlDisabledPackages,
- new StringSetPolicySerializer());
+ new PackageSetPolicySerializer());
// This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
// actual policy with the correct arguments (i.e. packageName) when reading the policies from
@@ -328,7 +328,7 @@ final class PolicyDefinition<V> {
new MostRecent<>(),
POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
(Set<String> value, Context context, Integer userId, PolicyKey policyKey) -> true,
- new StringSetPolicySerializer());
+ new PackageSetPolicySerializer());
static PolicyDefinition<Boolean> SCREEN_CAPTURE_DISABLED = new PolicyDefinition<>(
@@ -684,7 +684,7 @@ final class PolicyDefinition<V> {
void savePolicyValueToXml(TypedXmlSerializer serializer, V value)
throws IOException {
- mPolicySerializer.saveToXml(mPolicyKey, serializer, value);
+ mPolicySerializer.saveToXml(serializer, value);
}
@Nullable
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index eeb49765cc9d..4bf3ff4265d4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -375,6 +375,7 @@ final class PolicyEnforcerCallbacks {
private static void suspendPersonalAppsInPackageManager(Context context, int userId) {
final String[] appsToSuspend = PersonalAppsSuspensionHelper.forUser(context, userId)
.getPersonalAppsForSuspension();
+ Slogf.i(LOG_TAG, "Suspending personal apps: %s", String.join(",", appsToSuspend));
final String[] failedApps = LocalServices.getService(PackageManagerInternal.class)
.setPackagesSuspendedByAdmin(userId, appsToSuspend, true);
if (!ArrayUtils.isEmpty(failedApps)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java
index 5af2fa285483..e83b031fd3c0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java
@@ -17,7 +17,6 @@
package com.android.server.devicepolicy;
import android.annotation.NonNull;
-import android.app.admin.PolicyKey;
import android.app.admin.PolicyValue;
import com.android.modules.utils.TypedXmlPullParser;
@@ -26,7 +25,6 @@ import com.android.modules.utils.TypedXmlSerializer;
import java.io.IOException;
abstract class PolicySerializer<V> {
- abstract void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull V value)
- throws IOException;
+ abstract void saveToXml(TypedXmlSerializer serializer, @NonNull V value) throws IOException;
abstract PolicyValue<V> readFromXml(TypedXmlPullParser parser);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8755a8077ddb..cfe4e17eb1be 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -47,6 +47,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
+import android.crashrecovery.flags.Flags;
import android.credentials.CredentialManager;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
@@ -1195,11 +1196,13 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
t.traceEnd();
- // Now that we have the bare essentials of the OS up and running, take
- // note that we just booted, which might send out a rescue party if
- // we're stuck in a runtime restart loop.
- RescueParty.registerHealthObserver(mSystemContext);
- PackageWatchdog.getInstance(mSystemContext).noteBoot();
+ if (!Flags.recoverabilityDetection()) {
+ // Now that we have the bare essentials of the OS up and running, take
+ // note that we just booted, which might send out a rescue party if
+ // we're stuck in a runtime restart loop.
+ RescueParty.registerHealthObserver(mSystemContext);
+ PackageWatchdog.getInstance(mSystemContext).noteBoot();
+ }
// Manages LEDs and display backlight so we need it to bring up the display.
t.traceBegin("StartLightsService");
@@ -1469,9 +1472,12 @@ public final class SystemServer implements Dumpable {
boolean enableVrService = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
- // For debugging RescueParty
- if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
- throw new RuntimeException();
+ if (!Flags.recoverabilityDetection()) {
+ // For debugging RescueParty
+ if (Build.IS_DEBUGGABLE
+ && SystemProperties.getBoolean("debug.crash_system", false)) {
+ throw new RuntimeException();
+ }
}
try {
@@ -2910,6 +2916,14 @@ public final class SystemServer implements Dumpable {
mPackageManagerService.systemReady();
t.traceEnd();
+ if (Flags.recoverabilityDetection()) {
+ // Now that we have the essential services needed for rescue party, initialize
+ // RescuParty. note that we just booted, which might send out a rescue party if
+ // we're stuck in a runtime restart loop.
+ RescueParty.registerHealthObserver(mSystemContext);
+ PackageWatchdog.getInstance(mSystemContext).noteBoot();
+ }
+
t.traceBegin("MakeDisplayManagerServiceReady");
try {
// TODO: use boot phase and communicate this flag some other way
@@ -3313,6 +3327,14 @@ public final class SystemServer implements Dumpable {
* are updated outside of OTA; and to avoid breaking dependencies from system into apexes.
*/
private void startApexServices(@NonNull TimingsTraceAndSlog t) {
+ if (Flags.recoverabilityDetection()) {
+ // For debugging RescueParty
+ if (Build.IS_DEBUGGABLE
+ && SystemProperties.getBoolean("debug.crash_system", false)) {
+ throw new RuntimeException();
+ }
+ }
+
t.traceBegin("startApexServices");
// TODO(b/192880996): get the list from "android" package, once the manifest entries
// are migrated to system manifest.
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 87af841b901c..9e4f8219ea96 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -63,11 +63,8 @@ class AppIdPermissionPolicy : SchemePolicy() {
private val privilegedPermissionAllowlistViolations = MutableIndexedSet<String>()
- /**
- * Test-only switch to enforce signature permission allowlist even on debuggable builds.
- */
- @Volatile
- var isSignaturePermissionAllowlistForceEnforced = false
+ /** Test-only switch to enforce signature permission allowlist even on debuggable builds. */
+ @Volatile var isSignaturePermissionAllowlistForceEnforced = false
override val subjectScheme: String
get() = UidUri.SCHEME
@@ -108,8 +105,8 @@ class AppIdPermissionPolicy : SchemePolicy() {
val changedPermissionNames = MutableIndexedSet<String>()
packageNames.forEachIndexed { _, packageName ->
// The package may still be removed even if it was once notified as installed.
- val packageState = newState.externalState.packageStates[packageName]
- ?: return@forEachIndexed
+ val packageState =
+ newState.externalState.packageStates[packageName] ?: return@forEachIndexed
adoptPermissions(packageState, changedPermissionNames)
addPermissionGroups(packageState)
addPermissions(packageState, changedPermissionNames)
@@ -122,14 +119,14 @@ class AppIdPermissionPolicy : SchemePolicy() {
}
packageNames.forEachIndexed { _, packageName ->
- val packageState = newState.externalState.packageStates[packageName]
- ?: return@forEachIndexed
+ val packageState =
+ newState.externalState.packageStates[packageName] ?: return@forEachIndexed
val installedPackageState = if (isSystemUpdated) packageState else null
evaluateAllPermissionStatesForPackage(packageState, installedPackageState)
}
packageNames.forEachIndexed { _, packageName ->
- val packageState = newState.externalState.packageStates[packageName]
- ?: return@forEachIndexed
+ val packageState =
+ newState.externalState.packageStates[packageName] ?: return@forEachIndexed
newState.externalState.userIds.forEachIndexed { _, userId ->
inheritImplicitPermissionStates(packageState.appId, userId)
}
@@ -1775,6 +1772,7 @@ class AppIdPermissionPolicy : SchemePolicy() {
Manifest.permission.READ_MEDIA_AUDIO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VIDEO,
+ Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
)
private val NEARBY_DEVICES_PERMISSIONS =
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 79f1574105ba..7d58a2e53693 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -778,6 +778,49 @@ public final class UserManagerServiceTest {
}
@Test
+ public void testGetAliveUsers_shouldExcludeInitialisedEphemeralNonCurrentUsers() {
+ assertWithMessage("Ephemeral user should not exist at all initially")
+ .that(mUmi.getUsers(false).stream().anyMatch(u -> u.id == USER_ID))
+ .isFalse();
+
+ // add an ephemeral full user
+ TestUserData userData = new TestUserData(USER_ID);
+ userData.info.flags = UserInfo.FLAG_FULL | UserInfo.FLAG_EPHEMERAL;
+ addUserData(userData);
+
+ assertWithMessage("Ephemeral user should exist as alive after being created")
+ .that(mUmi.getUsers(true).stream().anyMatch(u -> u.id == USER_ID))
+ .isTrue();
+
+ // mock switch to the user (mark it as initialized & make it the current user)
+ userData.info.flags |= UserInfo.FLAG_INITIALIZED;
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("Ephemeral user should still exist as alive after being switched to")
+ .that(mUmi.getUsers(true).stream().anyMatch(u -> u.id == USER_ID))
+ .isTrue();
+
+ // switch away from the user
+ mockCurrentUser(OTHER_USER_ID);
+
+ assertWithMessage("Ephemeral user should not exist as alive after getting switched away")
+ .that(mUmi.getUsers(true).stream().anyMatch(u -> u.id == USER_ID))
+ .isFalse();
+
+ assertWithMessage("Ephemeral user should still exist as dying after getting switched away")
+ .that(mUmi.getUsers(false).stream().anyMatch(u -> u.id == USER_ID))
+ .isTrue();
+
+ // finally remove the user
+ mUms.removeUserInfo(USER_ID);
+
+ assertWithMessage("Ephemeral user should not exist at all after cleanup")
+ .that(mUmi.getUsers(false).stream().anyMatch(u -> u.id == USER_ID))
+ .isFalse();
+ }
+
+
+ @Test
@RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})
public void testCreatePrivateProfileOnHeadlessSystemUser_shouldAllowCreation() {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index 16d05b157727..6e6d5a870031 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -89,6 +89,7 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.test.FakePermissionEnforcer;
import android.util.Pair;
import android.view.Display;
import android.view.KeyEvent;
@@ -181,6 +182,7 @@ public class AbstractAccessibilityServiceConnectionTest {
@Mock private FingerprintGestureDispatcher mMockFingerprintGestureDispatcher;
@Mock private MagnificationProcessor mMockMagnificationProcessor;
@Mock private RemoteCallback.OnResultListener mMockListener;
+ FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
@Before
public void setup() {
@@ -198,6 +200,8 @@ public class AbstractAccessibilityServiceConnectionTest {
PowerManager powerManager =
new PowerManager(mMockContext, mMockIPowerManager, mMockIThermalService, mHandler);
when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+ when(mMockContext.getSystemService(Context.PERMISSION_ENFORCER_SERVICE))
+ .thenReturn(mFakePermissionEnforcer);
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index cda8b01afceb..c4946f0b221e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -26,7 +26,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -56,6 +55,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.test.FakePermissionEnforcer;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -82,7 +82,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-
/**
* Tests for AccessibilityServiceConnection
*/
@@ -130,6 +129,7 @@ public class AccessibilityServiceConnectionTest {
IBrailleDisplayController mMockBrailleDisplayController;
@Mock
MotionEventInjector mMockMotionEventInjector;
+ FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
@@ -151,12 +151,14 @@ public class AccessibilityServiceConnectionTest {
when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
when(mMockContext.getSystemService(Context.DISPLAY_SERVICE))
.thenReturn(new DisplayManager(mMockContext));
+ when(mMockContext.getSystemService(Context.PERMISSION_ENFORCER_SERVICE))
+ .thenReturn(mFakePermissionEnforcer);
mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
- COMPONENT_NAME, mServiceInfo, SERVICE_ID, mHandler, new Object(),
- mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
- mMockWindowManagerInternal, mMockSystemActionPerformer,
- mMockA11yWindowManager, mMockActivityTaskManagerInternal);
+ COMPONENT_NAME, mServiceInfo, SERVICE_ID, mHandler, new Object(),
+ mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
+ mMockWindowManagerInternal, mMockSystemActionPerformer,
+ mMockA11yWindowManager, mMockActivityTaskManagerInternal);
when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
when(mMockSecurityPolicy.checkAccessibilityAccess(mConnection)).thenReturn(true);
}
@@ -317,6 +319,8 @@ public class AccessibilityServiceConnectionTest {
@Test
@RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
public void connectBluetoothBrailleDisplay() throws Exception {
+ mFakePermissionEnforcer.grant(Manifest.permission.BLUETOOTH_CONNECT);
+ mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
final String macAddress = "00:11:22:33:AA:BB";
final byte[] descriptor = {0x05, 0x41};
Bundle bd = new Bundle();
@@ -338,9 +342,6 @@ public class AccessibilityServiceConnectionTest {
@Test
@RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
public void connectBluetoothBrailleDisplay_throwsForMissingBluetoothConnectPermission() {
- doThrow(SecurityException.class).when(mMockContext)
- .enforceCallingPermission(eq(Manifest.permission.BLUETOOTH_CONNECT), any());
-
assertThrows(SecurityException.class,
() -> mConnection.connectBluetoothBrailleDisplay("unused",
mMockBrailleDisplayController));
@@ -349,6 +350,7 @@ public class AccessibilityServiceConnectionTest {
@Test
@RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
public void connectBluetoothBrailleDisplay_throwsForNullMacAddress() {
+ mFakePermissionEnforcer.grant(Manifest.permission.BLUETOOTH_CONNECT);
assertThrows(NullPointerException.class,
() -> mConnection.connectBluetoothBrailleDisplay(null,
mMockBrailleDisplayController));
@@ -357,6 +359,7 @@ public class AccessibilityServiceConnectionTest {
@Test
@RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
public void connectBluetoothBrailleDisplay_throwsForMisformattedMacAddress() {
+ mFakePermissionEnforcer.grant(Manifest.permission.BLUETOOTH_CONNECT);
assertThrows(IllegalArgumentException.class,
() -> mConnection.connectBluetoothBrailleDisplay("12:34",
mMockBrailleDisplayController));
@@ -365,6 +368,7 @@ public class AccessibilityServiceConnectionTest {
@Test
@RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
public void connectUsbBrailleDisplay() throws Exception {
+ mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
final String serialNumber = "myUsbDevice";
final byte[] descriptor = {0x05, 0x41};
Bundle bd = new Bundle();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
index 3d0db71ba17f..c0e5f760d05c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
@@ -38,6 +38,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Handler;
+import android.os.test.FakePermissionEnforcer;
import android.view.accessibility.AccessibilityEvent;
import com.android.server.wm.WindowManagerInternal;
@@ -79,6 +80,7 @@ public class ProxyAccessibilityServiceConnectionTest {
AccessibilityTrace mMockA11yTrace;
@Mock
WindowManagerInternal mMockWindowManagerInternal;
+ FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
ProxyAccessibilityServiceConnection mProxyConnection;
AccessibilityServiceInfo mAccessibilityServiceInfo;
private int mFocusStrokeWidthDefaultValue;
@@ -90,6 +92,8 @@ public class ProxyAccessibilityServiceConnectionTest {
MockitoAnnotations.initMocks(this);
when(mMockContext.getResources()).thenReturn(resources);
when(mMockSecurityPolicy.checkAccessibilityAccess(any())).thenReturn(true);
+ when(mMockContext.getSystemService(Context.PERMISSION_ENFORCER_SERVICE))
+ .thenReturn(mFakePermissionEnforcer);
mAccessibilityServiceInfo = new AccessibilityServiceInfo();
mProxyConnection = new ProxyAccessibilityServiceConnection(mMockContext, COMPONENT_NAME,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
index f1b356a2a0dc..52b33db556e6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
@@ -50,6 +50,7 @@ import android.graphics.Region;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.test.FakePermissionEnforcer;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -113,6 +114,7 @@ public class ProxyManagerTest {
@Mock private IBinder mMockServiceAsBinder;
@Mock private VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
@Mock private IVirtualDeviceManager mMockIVirtualDeviceManager;
+ FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
private int mFocusStrokeWidthDefaultValue;
private int mFocusColorDefaultValue;
@@ -132,6 +134,8 @@ public class ProxyManagerTest {
when(mMockContext.getMainExecutor())
.thenReturn(InstrumentationRegistry.getTargetContext().getMainExecutor());
+ when(mMockContext.getSystemService(Context.PERMISSION_ENFORCER_SERVICE))
+ .thenReturn(mFakePermissionEnforcer);
when(mMockVirtualDeviceManagerInternal.getDeviceIdsForUid(anyInt())).thenReturn(
new ArraySet(Set.of(DEVICE_ID)));
LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 95a1f5a8a52f..e24592e556ea 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -39,6 +39,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
+import android.os.test.FakePermissionEnforcer;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.WindowManager;
@@ -80,12 +81,15 @@ public class UiAutomationManagerTest {
@Mock IBinder mMockOwner;
@Mock IAccessibilityServiceClient mMockAccessibilityServiceClient;
@Mock IBinder mMockServiceAsBinder;
+ FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mock(KeyEventDispatcher.class));
+ when(mMockContext.getSystemService(Context.PERMISSION_ENFORCER_SERVICE))
+ .thenReturn(mFakePermissionEnforcer);
when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
diff --git a/services/tests/servicestests/src/com/android/server/autofill/SaveEventLoggerTest.java b/services/tests/servicestests/src/com/android/server/autofill/SaveEventLoggerTest.java
index 0bca59d4b379..9e5207817261 100644
--- a/services/tests/servicestests/src/com/android/server/autofill/SaveEventLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/autofill/SaveEventLoggerTest.java
@@ -55,31 +55,4 @@ public class SaveEventLoggerTest {
assertThat(latencySaveFinishMillis.getValue())
.isNotEqualTo(SaveEventLogger.UNINITIATED_TIMESTAMP);
}
-
- @Test
- public void testTimestampsNotInitialized() {
- SaveEventLogger mLogger =
- spy(SaveEventLogger.forSessionId(1, SaveEventLogger.UNINITIATED_TIMESTAMP));
-
- mLogger.maybeSetLatencySaveUiDisplayMillis();
- mLogger.maybeSetLatencySaveRequestMillis();
- mLogger.maybeSetLatencySaveFinishMillis();
- ArgumentCaptor<Long> latencySaveUiDisplayMillis = ArgumentCaptor.forClass(Long.class);
- ArgumentCaptor<Long> latencySaveRequestMillis = ArgumentCaptor.forClass(Long.class);
- ArgumentCaptor<Long> latencySaveFinishMillis = ArgumentCaptor.forClass(Long.class);
-
- verify(mLogger, times(1))
- .maybeSetLatencySaveUiDisplayMillis(latencySaveUiDisplayMillis.capture());
- verify(mLogger, times(1))
- .maybeSetLatencySaveRequestMillis(latencySaveRequestMillis.capture());
- verify(mLogger, times(1))
- .maybeSetLatencySaveFinishMillis(latencySaveFinishMillis.capture());
-
- assertThat(latencySaveUiDisplayMillis.getValue())
- .isEqualTo(SaveEventLogger.UNINITIATED_TIMESTAMP);
- assertThat(latencySaveRequestMillis.getValue())
- .isEqualTo(SaveEventLogger.UNINITIATED_TIMESTAMP);
- assertThat(latencySaveFinishMillis.getValue())
- .isEqualTo(SaveEventLogger.UNINITIATED_TIMESTAMP);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java
new file mode 100644
index 000000000000..0716a5c5561d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.biometrics;
+
+import static com.android.server.biometrics.sensors.BiometricNotificationUtils.NOTIFICATION_ID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Intent;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BiometricDanglingReceiverTest {
+ @Rule
+ public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ private BiometricDanglingReceiver mBiometricDanglingReceiver;
+
+ @Rule
+ public final TestableContext mContext = spy(new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), null));
+
+ @Mock
+ NotificationManager mNotificationManager;
+
+ @Mock
+ Intent mIntent;
+
+ @Captor
+ private ArgumentCaptor<Intent> mArgumentCaptor;
+
+ @Before
+ public void setUp() {
+ mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
+ }
+
+ @Test
+ public void testFingerprintRegisterReceiver() {
+ initBroadcastReceiver(BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ verify(mContext).registerReceiver(eq(mBiometricDanglingReceiver), any());
+ }
+
+ @Test
+ public void testFaceRegisterReceiver() {
+ initBroadcastReceiver(BiometricsProtoEnums.MODALITY_FACE);
+ verify(mContext).registerReceiver(eq(mBiometricDanglingReceiver), any());
+ }
+
+ @Test
+ public void testOnReceive_fingerprintReEnrollLaunch() {
+ initBroadcastReceiver(BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ when(mIntent.getAction()).thenReturn(
+ BiometricDanglingReceiver.ACTION_FINGERPRINT_RE_ENROLL_LAUNCH);
+
+ mBiometricDanglingReceiver.onReceive(mContext, mIntent);
+
+ // Verify fingerprint enroll process is launched.
+ verify(mContext).startActivity(mArgumentCaptor.capture());
+ assertThat(mArgumentCaptor.getValue().getAction())
+ .isEqualTo(Settings.ACTION_FINGERPRINT_ENROLL);
+
+ // Verify notification is canceled
+ verify(mNotificationManager).cancelAsUser("FingerprintReEnroll", NOTIFICATION_ID,
+ UserHandle.CURRENT);
+
+ // Verify receiver is unregistered after receiving the broadcast
+ verify(mContext).unregisterReceiver(mBiometricDanglingReceiver);
+ }
+
+ @Test
+ public void testOnReceive_faceReEnrollLaunch() {
+ initBroadcastReceiver(BiometricsProtoEnums.MODALITY_FACE);
+ when(mIntent.getAction()).thenReturn(
+ BiometricDanglingReceiver.ACTION_FACE_RE_ENROLL_LAUNCH);
+
+ mBiometricDanglingReceiver.onReceive(mContext, mIntent);
+
+ // Verify face enroll process is launched.
+ verify(mContext).startActivity(mArgumentCaptor.capture());
+ assertThat(mArgumentCaptor.getValue().getAction())
+ .isEqualTo(BiometricDanglingReceiver.FACE_SETTINGS_ACTION);
+
+ // Verify notification is canceled
+ verify(mNotificationManager).cancelAsUser("FaceReEnroll", NOTIFICATION_ID,
+ UserHandle.CURRENT);
+
+ // Verify receiver is unregistered after receiving the broadcast.
+ verify(mContext).unregisterReceiver(mBiometricDanglingReceiver);
+ }
+
+ private void initBroadcastReceiver(int modality) {
+ mBiometricDanglingReceiver = new BiometricDanglingReceiver(mContext, modality);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index fc573d243129..37895315557a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -1228,6 +1228,11 @@ public class BiometricSchedulerTest {
Slog.d(TAG, "TestInternalEnumerateClient#startHalOperation");
onEnumerationResult(TEST_FINGERPRINT, 0 /* remaining */);
}
+
+ @Override
+ protected int getModality() {
+ return BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ }
}
private static class TestRemovalClient extends RemovalClient<Fingerprint, Object> {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java
index 9845b58f79bf..d8bdd50d8c08 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java
@@ -20,8 +20,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -79,15 +81,21 @@ public class FaceInternalEnumerateClientTest {
private final int mBiometricId = 1;
private final Face mFace = new Face("face", mBiometricId, 1 /* deviceId */);
private FaceInternalEnumerateClient mClient;
+ private boolean mNotificationSent;
@Before
public void setUp() {
when(mAidlSession.getSession()).thenReturn(mSession);
-
final List<Face> enrolled = new ArrayList<>();
enrolled.add(mFace);
- mClient = new FaceInternalEnumerateClient(mContext, () -> mAidlSession, mToken, USER_ID,
- TAG, enrolled, mBiometricUtils, SENSOR_ID, mBiometricLogger, mBiometricContext);
+ mClient = spy(new FaceInternalEnumerateClient(mContext, () -> mAidlSession, mToken, USER_ID,
+ TAG, enrolled, mBiometricUtils, SENSOR_ID, mBiometricLogger, mBiometricContext));
+
+ mNotificationSent = false;
+ doAnswer(invocation -> {
+ mNotificationSent = true;
+ return null;
+ }).when(mClient).sendDanglingNotification(anyList());
}
@Test
@@ -101,6 +109,7 @@ public class FaceInternalEnumerateClientTest {
verify(mSession).enumerateEnrollments();
assertThat(mClient.getUnknownHALTemplates().size()).isEqualTo(0);
+ assertThat(mNotificationSent).isFalse();
verify(mBiometricUtils, never()).removeBiometricForUser(any(), anyInt(), anyInt());
verify(mCallback).onClientFinished(mClient, true);
}
@@ -116,6 +125,7 @@ public class FaceInternalEnumerateClientTest {
verify(mSession).enumerateEnrollments();
assertThat(mClient.getUnknownHALTemplates().size()).isEqualTo(0);
+ assertThat(mNotificationSent).isFalse();
verify(mBiometricUtils, never()).removeBiometricForUser(any(), anyInt(), anyInt());
verify(mCallback, never()).onClientFinished(mClient, true);
}
@@ -131,6 +141,7 @@ public class FaceInternalEnumerateClientTest {
verify(mSession).enumerateEnrollments();
assertThat(mClient.getUnknownHALTemplates().size()).isEqualTo(0);
+ assertThat(mNotificationSent).isTrue();
verify(mBiometricUtils).removeBiometricForUser(mContext, USER_ID, mBiometricId);
verify(mCallback).onClientFinished(mClient, true);
}
@@ -147,6 +158,7 @@ public class FaceInternalEnumerateClientTest {
verify(mSession).enumerateEnrollments();
assertThat(mClient.getUnknownHALTemplates().size()).isEqualTo(1);
+ assertThat(mNotificationSent).isFalse();
verify(mBiometricUtils, never()).removeBiometricForUser(any(), anyInt(), anyInt());
verify(mCallback, never()).onClientFinished(mClient, true);
}
@@ -164,6 +176,7 @@ public class FaceInternalEnumerateClientTest {
verify(mSession).enumerateEnrollments();
assertThat(mClient.getUnknownHALTemplates().size()).isEqualTo(1);
+ assertThat(mNotificationSent).isTrue();
verify(mBiometricUtils).removeBiometricForUser(mContext, USER_ID, mBiometricId);
verify(mCallback).onClientFinished(mClient, true);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java
index b5df8362b09f..fab120016434 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java
@@ -20,8 +20,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -80,15 +82,23 @@ public class FingerprintInternalEnumerateClientTest {
private FingerprintInternalEnumerateClient mClient;
+ private boolean mNotificationSent;
+
@Before
public void setUp() {
when(mAidlSession.getSession()).thenReturn(mSession);
List<Fingerprint> enrolled = new ArrayList<>();
enrolled.add(new Fingerprint("one", 1, 1));
- mClient = new FingerprintInternalEnumerateClient(mContext, () -> mAidlSession, mToken,
+ mClient = spy(new FingerprintInternalEnumerateClient(mContext, () -> mAidlSession, mToken,
USER_ID, TAG, enrolled, mBiometricUtils, SENSOR_ID, mBiometricLogger,
- mBiometricContext);
+ mBiometricContext));
+
+ mNotificationSent = false;
+ doAnswer(invocation -> {
+ mNotificationSent = true;
+ return null;
+ }).when(mClient).sendDanglingNotification(anyList());
}
@Test
@@ -104,6 +114,7 @@ public class FingerprintInternalEnumerateClientTest {
assertThat(mClient.getUnknownHALTemplates().stream()
.flatMap(x -> Stream.of(x.getBiometricId()))
.collect(Collectors.toList())).containsExactly(2, 3);
+ assertThat(mNotificationSent).isTrue();
verify(mBiometricUtils).removeBiometricForUser(mContext, USER_ID, 1);
verify(mCallback).onClientFinished(mClient, true);
}
@@ -118,6 +129,7 @@ public class FingerprintInternalEnumerateClientTest {
verify(mSession).enumerateEnrollments();
assertThat(mClient.getUnknownHALTemplates().size()).isEqualTo(0);
+ assertThat(mNotificationSent).isFalse();
verify(mBiometricUtils, never()).removeBiometricForUser(any(), anyInt(), anyInt());
verify(mCallback).onClientFinished(mClient, true);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 855c6582dfec..b4cc3434e013 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -441,11 +441,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
@Override
public void runCryptoSelfTest() {}
- @Override
- public String[] getPersonalAppsForSuspension(int userId) {
- return new String[]{};
- }
-
public void setSystemCurrentTimeMillis(long value) {
mCurrentTimeMillis = value;
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 9a92c704c247..e1b66b53ecbe 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -106,6 +106,7 @@ public class HdmiControlServiceTest {
private HdmiPortInfo[] mHdmiPortInfo;
private ArrayList<Integer> mLocalDeviceTypes = new ArrayList<>();
private static final int PORT_ID_EARC_SUPPORTED = 3;
+ private static final int EARC_TRIGGER_START_ARC_ACTION_DELAY = 500;
@Before
public void setUp() throws Exception {
@@ -1374,6 +1375,11 @@ public class HdmiControlServiceTest {
PORT_ID_EARC_SUPPORTED);
verify(mHdmiControlServiceSpy, times(1))
.notifyEarcStatusToAudioService(eq(false), eq(new ArrayList<>()));
+ // ARC should be never initiated here. It should be started after 500 ms.
+ verify(mHdmiControlServiceSpy, times(0)).startArcAction(anyBoolean(), any());
+ // We move 500 ms forward because the action is only started 500 ms later.
+ mTestLooper.moveTimeForward(EARC_TRIGGER_START_ARC_ACTION_DELAY);
+ mTestLooper.dispatchAll();
verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(true), any());
}
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 5902caae443d..d0acaccf1de2 100644
--- a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -26,12 +26,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -39,9 +42,12 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.content.Context;
+import android.hardware.power.ChannelConfig;
+import android.hardware.power.IPower;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
import android.hardware.power.WorkDuration;
@@ -50,6 +56,7 @@ import android.os.IBinder;
import android.os.IHintSession;
import android.os.PerformanceHintManager;
import android.os.Process;
+import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -130,12 +137,15 @@ public class HintManagerServiceTest {
@Mock
private HintManagerService.NativeWrapper mNativeWrapperMock;
@Mock
+ private IPower mIPowerMock;
+ @Mock
private ActivityManagerInternal mAmInternalMock;
@Rule
public final CheckFlagsRule mCheckFlagsRule =
DeviceFlagsValueProvider.createCheckFlagsRule();
private HintManagerService mService;
+ private ChannelConfig mConfig;
private static Answer<Long> fakeCreateWithConfig(Long ptr, Long sessionId) {
return new Answer<Long>() {
@@ -149,6 +159,9 @@ public class HintManagerServiceTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mConfig = new ChannelConfig();
+ mConfig.readFlagBitmask = 1;
+ mConfig.writeFlagBitmask = 2;
when(mNativeWrapperMock.halGetHintSessionPreferredRate())
.thenReturn(DEFAULT_HINT_PREFERRED_RATE);
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_A),
@@ -170,6 +183,8 @@ public class HintManagerServiceTest {
any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[2],
SESSION_IDS[2]));
+ when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
+ when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
}
@@ -252,6 +267,9 @@ public class HintManagerServiceTest {
NativeWrapper createNativeWrapper() {
return mNativeWrapperMock;
}
+ IPower createIPower() {
+ return mIPowerMock;
+ }
});
return mService;
}
@@ -261,6 +279,9 @@ public class HintManagerServiceTest {
NativeWrapper createNativeWrapper() {
return new NativeWrapperFake();
}
+ IPower createIPower() {
+ return mIPowerMock;
+ }
});
return mService;
}
@@ -728,6 +749,102 @@ public class HintManagerServiceTest {
verify(mNativeWrapperMock, never()).halSetMode(anyLong(), anyInt(), anyBoolean());
}
+ @Test
+ public void testGetChannel() throws Exception {
+ HintManagerService service = createService();
+ Binder token = new Binder();
+
+ // Should only call once, after caching the first call
+ ChannelConfig config = service.getBinderServiceInstance().getSessionChannel(token);
+ ChannelConfig config2 = service.getBinderServiceInstance().getSessionChannel(token);
+ verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID));
+ assertEquals(config.readFlagBitmask, mConfig.readFlagBitmask);
+ assertEquals(config.writeFlagBitmask, mConfig.writeFlagBitmask);
+ assertEquals(config2.readFlagBitmask, mConfig.readFlagBitmask);
+ assertEquals(config2.writeFlagBitmask, mConfig.writeFlagBitmask);
+ }
+
+ @Test
+ public void testGetChannelTwice() throws Exception {
+ HintManagerService service = createService();
+ Binder token = new Binder();
+
+ service.getBinderServiceInstance().getSessionChannel(token);
+ verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID));
+ service.getBinderServiceInstance().closeSessionChannel();
+ verify(mIPowerMock, times(1)).closeSessionChannel(eq(TGID), eq(UID));
+
+ clearInvocations(mIPowerMock);
+
+ service.getBinderServiceInstance().getSessionChannel(token);
+ verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID));
+ service.getBinderServiceInstance().closeSessionChannel();
+ verify(mIPowerMock, times(1)).closeSessionChannel(eq(TGID), eq(UID));
+ }
+
+ @Test
+ public void testGetChannelFails() throws Exception {
+ HintManagerService service = createService();
+ Binder token = new Binder();
+
+ when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenThrow(RemoteException.class);
+
+ assertThrows(IllegalStateException.class, () -> {
+ service.getBinderServiceInstance().getSessionChannel(token);
+ });
+ }
+
+
+ @Test
+ public void testGetChannelBadVersion() throws Exception {
+ when(mIPowerMock.getInterfaceVersion()).thenReturn(3);
+ HintManagerService service = createService();
+ Binder token = new Binder();
+
+ reset(mIPowerMock);
+ when(mIPowerMock.getInterfaceVersion()).thenReturn(3);
+ when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
+
+ ChannelConfig channel = service.getBinderServiceInstance().getSessionChannel(token);
+ verify(mIPowerMock, times(0)).getSessionChannel(eq(TGID), eq(UID));
+ assertNull(channel);
+ }
+
+ @Test
+ public void testCloseChannel() throws Exception {
+ HintManagerService service = createService();
+ Binder token = new Binder();
+
+ service.getBinderServiceInstance().getSessionChannel(token);
+ service.getBinderServiceInstance().closeSessionChannel();
+ verify(mIPowerMock, times(1)).closeSessionChannel(eq(TGID), eq(UID));
+ }
+
+ @Test
+ public void testCloseChannelFails() throws Exception {
+ HintManagerService service = createService();
+ Binder token = new Binder();
+
+ service.getBinderServiceInstance().getSessionChannel(token);
+
+ doThrow(RemoteException.class).when(mIPowerMock).closeSessionChannel(anyInt(), anyInt());
+
+ assertThrows(IllegalStateException.class, () -> {
+ service.getBinderServiceInstance().closeSessionChannel();
+ });
+ }
+
+ @Test
+ public void testDoubleClose() throws Exception {
+ HintManagerService service = createService();
+ Binder token = new Binder();
+
+ service.getBinderServiceInstance().getSessionChannel(token);
+ service.getBinderServiceInstance().closeSessionChannel();
+ service.getBinderServiceInstance().closeSessionChannel();
+ verify(mIPowerMock, times(1)).closeSessionChannel(eq(TGID), eq(UID));
+ }
+
// This test checks that concurrent operations from different threads on IHintService,
// IHintSession and UidObserver will not cause data race or deadlock. Ideally we should also
// check the output of threads' reportActualDuration performance to detect lock starvation
@@ -935,4 +1052,40 @@ public class HintManagerServiceTest {
a.reportActualWorkDuration2(WORK_DURATIONS_FIVE);
verify(mNativeWrapperMock, never()).halReportActualWorkDuration(anyLong(), any(), any());
}
+
+ @Test
+ public void testChannelDiesWhenTokenDies() throws Exception {
+ HintManagerService service = createService();
+
+ class DyingToken extends Binder {
+ DeathRecipient mToNotify;
+ @Override
+ public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
+ mToNotify = recipient;
+ super.linkToDeath(recipient, flags);
+ }
+
+ public void fakeDeath() {
+ mToNotify.binderDied();
+ }
+ }
+
+ DyingToken token = new DyingToken();
+
+ service.getBinderServiceInstance().getSessionChannel(token);
+ verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID));
+ assertTrue(service.hasChannel(TGID, UID));
+
+ token.fakeDeath();
+
+ assertFalse(service.hasChannel(TGID, UID));
+ verify(mIPowerMock, times(1)).closeSessionChannel(eq(TGID), eq(UID));
+
+ clearInvocations(mIPowerMock);
+
+ token = new DyingToken();
+ service.getBinderServiceInstance().getSessionChannel(token);
+ verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID));
+ assertTrue(service.hasChannel(TGID, UID));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index b366f9203d6b..5e2fe6a080eb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -341,7 +341,6 @@ import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -503,7 +502,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Mock
MultiRateLimiter mToastRateLimiter;
BroadcastReceiver mPackageIntentReceiver;
- BroadcastReceiver mUserSwitchIntentReceiver;
+ BroadcastReceiver mUserIntentReceiver;
BroadcastReceiver mNotificationTimeoutReceiver;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
@@ -802,11 +801,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
&& filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
mPackageIntentReceiver = broadcastReceivers.get(i);
}
- if (filter.hasAction(Intent.ACTION_USER_SWITCHED)) {
+ if (filter.hasAction(Intent.ACTION_USER_SWITCHED)
+ || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)
+ || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
// There may be multiple receivers, get the NMS one
if (broadcastReceivers.get(i).toString().contains(
NotificationManagerService.class.getName())) {
- mUserSwitchIntentReceiver = broadcastReceivers.get(i);
+ mUserIntentReceiver = broadcastReceivers.get(i);
}
}
if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT)
@@ -815,7 +816,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
}
assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
- assertNotNull("User-switch receiver should exist", mUserSwitchIntentReceiver);
+ assertNotNull("User receiver should exist", mUserIntentReceiver);
if (!Flags.allNotifsNeedTtl()) {
assertNotNull("Notification timeout receiver should exist",
mNotificationTimeoutReceiver);
@@ -976,7 +977,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private void simulateProfileAvailabilityActions(String intentAction) {
final Intent intent = new Intent(intentAction);
intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE);
- mUserSwitchIntentReceiver.onReceive(mContext, intent);
+ mUserIntentReceiver.onReceive(mContext, intent);
}
private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() {
@@ -14482,13 +14483,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() {
+ mService.mZenModeHelper = mock(ZenModeHelper.class);
+ mService.setPreferencesHelper(mPreferencesHelper);
+
+ UserInfo prevUser = new UserInfo();
+ prevUser.id = 10;
+ UserInfo newUser = new UserInfo();
+ newUser.id = 20;
+
+ mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser));
+
+ InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
+ inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
+ inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
+ public void onUserSwitched_broadcast_updatesZenModeAndChannelsBypassingDnd() {
Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
intent.putExtra(Intent.EXTRA_USER_HANDLE, 20);
mService.mZenModeHelper = mock(ZenModeHelper.class);
mService.setPreferencesHelper(mPreferencesHelper);
- mUserSwitchIntentReceiver.onReceive(mContext, intent);
+ mUserIntentReceiver.onReceive(mContext, intent);
InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 5fdb3965be76..d1423fe71e50 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -3002,39 +3002,45 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(ZEN_MODE_OFF, mZenModeHelper.mZenMode);
}
- private enum ModesApiFlag {
- ENABLED(true, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_USER),
- DISABLED(false, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI);
+ private enum ModesFlag {
+ MODES_UI(2, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_USER),
+ MODES_API(1, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_USER),
+ DISABLED(0, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI);
- private final boolean mEnabled;
+ private final int mFlagsEnabled;
@ConfigChangeOrigin
private final int mOriginForUserActionInSystemUi;
- ModesApiFlag(boolean enabled, @ConfigChangeOrigin int originForUserActionInSystemUi) {
- this.mEnabled = enabled;
+ ModesFlag(int flagsEnabled, @ConfigChangeOrigin int originForUserActionInSystemUi) {
+ this.mFlagsEnabled = flagsEnabled;
this.mOriginForUserActionInSystemUi = originForUserActionInSystemUi;
}
- void applyFlag(SetFlagsRule setFlagsRule) {
- if (mEnabled) {
+ void applyFlags(SetFlagsRule setFlagsRule) {
+ if (mFlagsEnabled >= 1) {
setFlagsRule.enableFlags(Flags.FLAG_MODES_API);
} else {
setFlagsRule.disableFlags(Flags.FLAG_MODES_API);
}
+ if (mFlagsEnabled >= 2) {
+ setFlagsRule.enableFlags(Flags.FLAG_MODES_UI);
+ } else {
+ setFlagsRule.disableFlags(Flags.FLAG_MODES_UI);
+ }
}
}
@Test
- public void testZenModeEventLog_setManualZenMode(@TestParameter ModesApiFlag modesApiFlag)
+ public void testZenModeEventLog_setManualZenMode(@TestParameter ModesFlag modesFlag)
throws IllegalArgumentException {
- modesApiFlag.applyFlag(mSetFlagsRule);
+ modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
// Turn zen mode on (to important_interruptions)
// Need to additionally call the looper in order to finish the post-apply-config process
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
- modesApiFlag.mOriginForUserActionInSystemUi, "", null, Process.SYSTEM_UID);
+ modesFlag.mOriginForUserActionInSystemUi, "", null, Process.SYSTEM_UID);
// Now turn zen mode off, but via a different package UID -- this should get registered as
// "not an action by the user" because some other app is changing zen mode
@@ -3062,7 +3068,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(0));
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
assertThat(mZenModeEventLogger.getFromSystemOrSystemUi(0)).isEqualTo(
- modesApiFlag == ModesApiFlag.DISABLED);
+ modesFlag == ModesFlag.DISABLED);
assertTrue(mZenModeEventLogger.getIsUserAction(0));
assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(0));
checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0));
@@ -3091,9 +3097,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void testZenModeEventLog_automaticRules(@TestParameter ModesApiFlag modesApiFlag)
+ public void testZenModeEventLog_automaticRules(@TestParameter ModesFlag modesFlag)
throws IllegalArgumentException {
- modesApiFlag.applyFlag(mSetFlagsRule);
+ modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3116,7 +3122,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Event 2: "User" turns off the automatic rule (sets it to not enabled)
zenRule.setEnabled(false);
mZenModeHelper.updateAutomaticZenRule(id, zenRule,
- modesApiFlag.mOriginForUserActionInSystemUi, "", Process.SYSTEM_UID);
+ modesFlag.mOriginForUserActionInSystemUi, "", Process.SYSTEM_UID);
// Add a new system rule
AutomaticZenRule systemRule = new AutomaticZenRule("systemRule",
@@ -3134,7 +3140,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Event 4: "User" deletes the rule
- mZenModeHelper.removeAutomaticZenRule(systemId, modesApiFlag.mOriginForUserActionInSystemUi,
+ mZenModeHelper.removeAutomaticZenRule(systemId, modesFlag.mOriginForUserActionInSystemUi,
"", Process.SYSTEM_UID);
// In total, this represents 4 events
@@ -3282,22 +3288,22 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void testZenModeEventLog_policyChanges(@TestParameter ModesApiFlag modesApiFlag)
+ public void testZenModeEventLog_policyChanges(@TestParameter ModesFlag modesFlag)
throws IllegalArgumentException {
- modesApiFlag.applyFlag(mSetFlagsRule);
+ modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
// First just turn zen mode on
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
- modesApiFlag.mOriginForUserActionInSystemUi, "", null, Process.SYSTEM_UID);
+ modesFlag.mOriginForUserActionInSystemUi, "", null, Process.SYSTEM_UID);
// Now change the policy slightly; want to confirm that this'll be reflected in the logs
ZenModeConfig newConfig = mZenModeHelper.mConfig.copy();
newConfig.allowAlarms = true;
newConfig.allowRepeatCallers = false;
mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(),
- modesApiFlag.mOriginForUserActionInSystemUi, Process.SYSTEM_UID);
+ modesFlag.mOriginForUserActionInSystemUi, Process.SYSTEM_UID);
// Turn zen mode off; we want to make sure policy changes do not get logged when zen mode
// is off.
@@ -3308,7 +3314,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
newConfig.allowMessages = false;
newConfig.allowRepeatCallers = true;
mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(),
- modesApiFlag.mOriginForUserActionInSystemUi, Process.SYSTEM_UID);
+ modesFlag.mOriginForUserActionInSystemUi, Process.SYSTEM_UID);
// Total events: we only expect ones for turning on, changing policy, and turning off
assertEquals(3, mZenModeEventLogger.numLoggedChanges());
@@ -3341,9 +3347,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void testZenModeEventLog_ruleCounts(@TestParameter ModesApiFlag modesApiFlag)
+ public void testZenModeEventLog_ruleCounts(@TestParameter ModesFlag modesFlag)
throws IllegalArgumentException {
- modesApiFlag.applyFlag(mSetFlagsRule);
+ modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3447,9 +3453,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenModeEventLog_noLogWithNoConfigChange(
- @TestParameter ModesApiFlag modesApiFlag) throws IllegalArgumentException {
+ @TestParameter ModesFlag modesFlag) throws IllegalArgumentException {
// If evaluateZenMode is called independently of a config change, don't log.
- modesApiFlag.applyFlag(mSetFlagsRule);
+ modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3466,11 +3472,11 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void testZenModeEventLog_reassignUid(@TestParameter ModesApiFlag modesApiFlag)
+ public void testZenModeEventLog_reassignUid(@TestParameter ModesFlag modesFlag)
throws IllegalArgumentException {
// Test that, only in specific cases, we reassign the calling UID to one associated with
// the automatic rule owner.
- modesApiFlag.applyFlag(mSetFlagsRule);
+ modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3496,7 +3502,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
manualRulePolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2,
- modesApiFlag.mOriginForUserActionInSystemUi, "test", Process.SYSTEM_UID);
+ modesFlag.mOriginForUserActionInSystemUi, "test", Process.SYSTEM_UID);
// Turn on rule 1; call looks like it's from the system. Because setting a condition is
// typically an automatic (non-user-initiated) action, expect the calling UID to be
@@ -3515,7 +3521,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// from the system-provided one.
zenRule.setEnabled(false);
mZenModeHelper.updateAutomaticZenRule(id, zenRule,
- modesApiFlag.mOriginForUserActionInSystemUi, "", Process.SYSTEM_UID);
+ modesFlag.mOriginForUserActionInSystemUi, "", Process.SYSTEM_UID);
// Add a manual rule. Any manual rule changes should not get calling uids reassigned.
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, UPDATE_ORIGIN_APP,
@@ -3573,9 +3579,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenModeEventLog_channelsBypassingChanges(
- @TestParameter ModesApiFlag modesApiFlag) {
+ @TestParameter ModesFlag modesFlag) {
// Verify that the right thing happens when the canBypassDnd value changes.
- modesApiFlag.applyFlag(mSetFlagsRule);
+ modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3847,8 +3853,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_modesApiDefaultRulesOnly_takesDeviceDefault() {
+ public void testUpdateConsolidatedPolicy_modesApiDefaultRulesOnly_takesDefault(
+ @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
+ modesFlag.applyFlags(mSetFlagsRule);
setupZenConfig();
// When there's one automatic rule active and it doesn't specify a policy, test that the
@@ -3869,7 +3876,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// inspect the consolidated policy, which should match the device default settings.
assertThat(ZenAdapters.notificationPolicyToZenPolicy(mZenModeHelper.mConsolidatedPolicy))
- .isEqualTo(mZenModeHelper.getDefaultZenPolicy());
+ .isEqualTo(modesFlag == ModesFlag.MODES_UI
+ ? mZenModeHelper.getDefaultZenPolicy()
+ : mZenModeHelper.mConfig.toZenPolicy());
}
@Test
@@ -3904,7 +3913,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// since this is the only active rule, the consolidated policy should match the custom
- // policy for every field specified, and take default values for unspecified things
+ // policy for every field specified, and take default values (from device default or
+ // manual policy) for unspecified things
assertTrue(mZenModeHelper.mConsolidatedPolicy.allowAlarms()); // custom
assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMedia()); // custom
assertFalse(mZenModeHelper.mConsolidatedPolicy.allowSystem()); // default
@@ -3918,8 +3928,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_modesApiCustomPolicyOnly_fillInWithDeviceDefault() {
+ public void testUpdateConsolidatedPolicy_modesApiCustomPolicyOnly_fillInWithDefault(
+ @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
+ modesFlag.applyFlags(mSetFlagsRule);
setupZenConfig();
// when there's only one automatic rule active and it has a custom policy, make sure that's
@@ -3948,11 +3959,15 @@ public class ZenModeHelperTest extends UiServiceTestCase {
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// since this is the only active rule, the consolidated policy should match the custom
- // policy for every field specified, and take default values for unspecified things
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isTrue(); // default
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // default
+ // policy for every field specified, and take default values (from either device default
+ // policy or manual rule) for unspecified things
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? true : false); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? true : false); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isTrue(); // custom
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isFalse(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? false : true); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isFalse(); // custom
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers()).isFalse(); // custom
@@ -4022,8 +4037,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_modesApiDefaultAndCustomActive_mergesWithDefault() {
+ public void testUpdateConsolidatedPolicy_modesApiDefaultAndCustomActive_mergesWithDefault(
+ @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
+ modesFlag.applyFlags(mSetFlagsRule);
setupZenConfig();
// when there are two rules active, one inheriting the default policy and one setting its
@@ -4071,16 +4087,19 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// now both rules should be on, and the consolidated policy should reflect the most
// restrictive option of each of the two
assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isFalse(); // custom stricter
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? true : false); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isFalse(); // default stricter
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isFalse(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? false : true); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isFalse(); // custom stricter
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers())
.isFalse(); // custom stricter
assertThat(mZenModeHelper.mConsolidatedPolicy.showBadges()).isFalse(); // custom stricter
- assertThat(mZenModeHelper.mConsolidatedPolicy.showPeeking()).isFalse(); // default stricter
+ assertThat(mZenModeHelper.mConsolidatedPolicy.showPeeking()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? false : true); // default
}
@Test
@@ -4134,8 +4153,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_ignoresActiveRulesWithInterruptionFilterAll() {
+ public void testUpdateConsolidatedPolicy_ignoresActiveRulesWithInterruptionFilterAll(
+ @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
+ modesFlag.applyFlags(mSetFlagsRule);
setupZenConfig();
// Rules with INTERRUPTION_FILTER_ALL are skipped when calculating consolidated policy.
@@ -4172,10 +4192,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
UPDATE_ORIGIN_APP, CUSTOM_PKG_UID);
// Consolidated Policy should be default + rule1.
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? true : false); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // priority rule
assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isTrue(); // priority rule
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isFalse(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isEqualTo(
+ modesFlag == ModesFlag.MODES_UI ? false : true); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default
@@ -6251,7 +6273,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
private void checkDndProtoMatchesDefaultZenConfig(DNDPolicyProto dndProto) {
- if (!Flags.modesApi()) {
+ if (!Flags.modesUi()) {
checkDndProtoMatchesSetupZenConfig(dndProto);
return;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 10eae577f706..13550923cf3d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -46,7 +46,6 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
-import static android.server.wm.ActivityManagerTestBase.isTablet;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
@@ -76,7 +75,6 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -124,7 +122,6 @@ import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker;
-import com.android.window.flags.Flags;
import org.junit.After;
import org.junit.Before;
@@ -1298,12 +1295,6 @@ public class ActivityStarterTests extends WindowTestsBase {
*/
@Test
public void testDeliverIntentToTopActivityOfNonTopDisplay() {
- // TODO(b/330152508): Remove check once legacy multi-display behaviour can coexist with
- // desktop windowing mode
- // Ignore test if desktop windowing is enabled on tablets as legacy multi-display
- // behaviour will not be respected
- assumeFalse(Flags.enableDesktopWindowingMode() && isTablet());
-
final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
false /* mockGetRootTask */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
index 695faa525dd6..39a2259cf77f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
@@ -19,6 +19,8 @@ package com.android.server.wm;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PERMISSION;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
+import static com.android.window.flags.Flags.balImprovedMetrics;
import static com.google.common.truth.Truth.assertThat;
@@ -145,6 +147,16 @@ public class BackgroundActivityStartControllerTests {
}
@Override
+ boolean shouldLogStats(BalVerdict finalVerdict, BalState state) {
+ return true;
+ }
+
+ @Override
+ boolean shouldLogIntentActivity(BalVerdict finalVerdict, BalState state) {
+ return true;
+ }
+
+ @Override
BalVerdict checkBackgroundActivityStartAllowedByCaller(BalState state) {
return mCallerVerdict.orElseGet(
() -> super.checkBackgroundActivityStartAllowedByCaller(state));
@@ -238,7 +250,12 @@ public class BackgroundActivityStartControllerTests {
// assertions
assertThat(verdict.getCode()).isEqualTo(BackgroundActivityStartController.BAL_BLOCK);
- assertThat(mBalAllowedLogs).isEmpty(); // not allowed
+ if (balImprovedMetrics()) {
+ assertThat(mBalAllowedLogs).containsExactly(
+ new BalAllowedLog("package.app3/someClass", BAL_BLOCK));
+ } else {
+ assertThat(mBalAllowedLogs).isEmpty(); // not allowed
+ }
}
// Tests for BackgroundActivityStartController.checkBackgroundActivityStart
@@ -268,7 +285,12 @@ public class BackgroundActivityStartControllerTests {
// assertions
assertThat(verdict).isEqualTo(BalVerdict.BLOCK);
- assertThat(mBalAllowedLogs).isEmpty(); // not allowed
+ if (balImprovedMetrics()) {
+ assertThat(mBalAllowedLogs).containsExactly(
+ new BalAllowedLog("package.app3/someClass", BAL_BLOCK));
+ } else {
+ assertThat(mBalAllowedLogs).isEmpty(); // not allowed
+ }
}
@Test
@@ -298,7 +320,12 @@ public class BackgroundActivityStartControllerTests {
// assertions
assertThat(verdict).isEqualTo(callerVerdict);
- assertThat(mBalAllowedLogs).isEmpty(); // non-critical exception
+ if (balImprovedMetrics()) {
+ assertThat(mBalAllowedLogs).containsExactly(
+ new BalAllowedLog("package.app3/someClass", callerVerdict.getCode()));
+ } else {
+ assertThat(mBalAllowedLogs).isEmpty(); // non-critical exception
+ }
}
@Test
@@ -362,7 +389,13 @@ public class BackgroundActivityStartControllerTests {
// assertions
assertThat(verdict).isEqualTo(callerVerdict);
- assertThat(mBalAllowedLogs).containsExactly(new BalAllowedLog("", callerVerdict.getCode()));
+ if (balImprovedMetrics()) {
+ assertThat(mBalAllowedLogs).containsExactly(
+ new BalAllowedLog("package.app3/someClass", callerVerdict.getCode()));
+ } else {
+ assertThat(mBalAllowedLogs).containsExactly(
+ new BalAllowedLog("", callerVerdict.getCode()));
+ }
}
@Test
@@ -398,7 +431,12 @@ public class BackgroundActivityStartControllerTests {
// assertions
assertThat(verdict).isEqualTo(BalVerdict.BLOCK);
- assertThat(mBalAllowedLogs).isEmpty();
+ if (balImprovedMetrics()) {
+ assertThat(mBalAllowedLogs).containsExactly(
+ new BalAllowedLog("package.app3/someClass", BAL_BLOCK));
+ } else {
+ assertThat(mBalAllowedLogs).isEmpty();
+ }
}
@Test
@@ -430,7 +468,12 @@ public class BackgroundActivityStartControllerTests {
// assertions
assertThat(verdict).isEqualTo(callerVerdict);
- assertThat(mBalAllowedLogs).isEmpty();
+ if (balImprovedMetrics()) {
+ assertThat(mBalAllowedLogs).containsExactly(
+ new BalAllowedLog("package.app3/someClass", callerVerdict.getCode()));
+ } else {
+ assertThat(mBalAllowedLogs).isEmpty();
+ }
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index f92387cdf5c9..a268aa912183 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -79,19 +79,19 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase {
@Test
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void testReturnsContinueIfDesktopWindowingIsDisabled() {
+ public void testReturnsSkipIfDesktopWindowingIsDisabled() {
setupDesktopModeLaunchParamsModifier();
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(null).calculate());
+ assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(null).calculate());
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void testReturnsContinueIfDesktopWindowingIsEnabledOnUnsupportedDevice() {
+ public void testReturnsSkipIfDesktopWindowingIsEnabledOnUnsupportedDevice() {
setupDesktopModeLaunchParamsModifier(/*isDesktopModeSupported=*/ false,
/*enforceDeviceRestrictions=*/ true);
- assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(null).calculate());
+ assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(null).calculate());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index b74da1a888cd..a60d243c9dad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -85,6 +85,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
import android.view.InsetsState;
@@ -96,6 +98,7 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.window.flags.Flags;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -1528,6 +1531,98 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mActivity.getParent().getConfiguration()), /* delta */ 0.01);
}
+ @Test
+ public void testIsVerticalThinLetterboxed() {
+ // Vertical thin letterbox disabled
+ doReturn(-1).when(mActivity.mWmService.mLetterboxConfiguration)
+ .getThinLetterboxHeightPx();
+ assertFalse(mController.isVerticalThinLetterboxed());
+ // Define a Task 100x100
+ final Task task = mock(Task.class);
+ doReturn(new Rect(0, 0, 100, 100)).when(task).getBounds();
+ doReturn(10).when(mActivity.mWmService.mLetterboxConfiguration)
+ .getThinLetterboxHeightPx();
+
+ // Vertical thin letterbox disabled without Task
+ doReturn(null).when(mActivity).getTask();
+ assertFalse(mController.isVerticalThinLetterboxed());
+ // Assign a Task for the Activity
+ doReturn(task).when(mActivity).getTask();
+
+ // (task.width() - act.width()) / 2 = 5 < 10
+ doReturn(new Rect(5, 5, 95, 95)).when(mActivity).getBounds();
+ assertTrue(mController.isVerticalThinLetterboxed());
+
+ // (task.width() - act.width()) / 2 = 10 = 10
+ doReturn(new Rect(10, 10, 90, 90)).when(mActivity).getBounds();
+ assertTrue(mController.isVerticalThinLetterboxed());
+
+ // (task.width() - act.width()) / 2 = 11 > 10
+ doReturn(new Rect(11, 11, 89, 89)).when(mActivity).getBounds();
+ assertFalse(mController.isVerticalThinLetterboxed());
+ }
+
+ @Test
+ public void testIsHorizontalThinLetterboxed() {
+ // Horizontal thin letterbox disabled
+ doReturn(-1).when(mActivity.mWmService.mLetterboxConfiguration)
+ .getThinLetterboxWidthPx();
+ assertFalse(mController.isHorizontalThinLetterboxed());
+ // Define a Task 100x100
+ final Task task = mock(Task.class);
+ doReturn(new Rect(0, 0, 100, 100)).when(task).getBounds();
+ doReturn(10).when(mActivity.mWmService.mLetterboxConfiguration)
+ .getThinLetterboxWidthPx();
+
+ // Vertical thin letterbox disabled without Task
+ doReturn(null).when(mActivity).getTask();
+ assertFalse(mController.isHorizontalThinLetterboxed());
+ // Assign a Task for the Activity
+ doReturn(task).when(mActivity).getTask();
+
+ // (task.height() - act.height()) / 2 = 5 < 10
+ doReturn(new Rect(5, 5, 95, 95)).when(mActivity).getBounds();
+ assertTrue(mController.isHorizontalThinLetterboxed());
+
+ // (task.height() - act.height()) / 2 = 10 = 10
+ doReturn(new Rect(10, 10, 90, 90)).when(mActivity).getBounds();
+ assertTrue(mController.isHorizontalThinLetterboxed());
+
+ // (task.height() - act.height()) / 2 = 11 > 10
+ doReturn(new Rect(11, 11, 89, 89)).when(mActivity).getBounds();
+ assertFalse(mController.isHorizontalThinLetterboxed());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_REACHABILITY)
+ public void testAllowReachabilityForThinLetterboxWithFlagEnabled() {
+ spyOn(mController);
+ doReturn(true).when(mController).isVerticalThinLetterboxed();
+ assertFalse(mController.allowVerticalReachabilityForThinLetterbox());
+ doReturn(true).when(mController).isHorizontalThinLetterboxed();
+ assertFalse(mController.allowHorizontalReachabilityForThinLetterbox());
+
+ doReturn(false).when(mController).isVerticalThinLetterboxed();
+ assertTrue(mController.allowVerticalReachabilityForThinLetterbox());
+ doReturn(false).when(mController).isHorizontalThinLetterboxed();
+ assertTrue(mController.allowHorizontalReachabilityForThinLetterbox());
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_REACHABILITY)
+ public void testAllowReachabilityForThinLetterboxWithFlagDisabled() {
+ spyOn(mController);
+ doReturn(true).when(mController).isVerticalThinLetterboxed();
+ assertTrue(mController.allowVerticalReachabilityForThinLetterbox());
+ doReturn(true).when(mController).isHorizontalThinLetterboxed();
+ assertTrue(mController.allowHorizontalReachabilityForThinLetterbox());
+
+ doReturn(false).when(mController).isVerticalThinLetterboxed();
+ assertTrue(mController.allowVerticalReachabilityForThinLetterbox());
+ doReturn(false).when(mController).isHorizontalThinLetterboxed();
+ assertTrue(mController.allowHorizontalReachabilityForThinLetterbox());
+ }
+
private void mockThatProperty(String propertyName, boolean value) throws Exception {
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
/* className */ "");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 75b84d1c8a64..6ec1429200e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1373,26 +1373,6 @@ public class RecentTasksTest extends WindowTestsBase {
assertTrue(info.supportsMultiWindow);
}
- @Test
- public void testRemoveCompatibleRecentTask() {
- final Task task1 = createTaskBuilder(".Task").setWindowingMode(
- WINDOWING_MODE_FULLSCREEN).build();
- mRecentTasks.add(task1);
- final Task task2 = createTaskBuilder(".Task").setWindowingMode(
- WINDOWING_MODE_MULTI_WINDOW).build();
- mRecentTasks.add(task2);
- assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
- true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
-
- // Set windowing mode and ensure the same fullscreen task that created earlier is removed.
- task2.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- mRecentTasks.removeCompatibleRecentTask(task2);
- assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
- true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
- assertEquals(task2.mTaskId, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
- true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().get(0).taskId);
- }
-
private TaskSnapshot createSnapshot(Point taskSize, Point bufferSize) {
HardwareBuffer buffer = null;
if (bufferSize != null) {
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 8677738f3edc..6b605ec6d0c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -3646,11 +3646,27 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testIsReachabilityEnabled_thisLetterbox_false() {
+ // Case when the reachability would be enabled otherwise
+ setUpDisplaySizeWithApp(/* dw */ 1000, /* dh */ 2800);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+ mActivity.getWindowConfiguration().setBounds(null);
+
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ false);
+
+ assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
+ assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
+ }
+
+ @Test
public void testIsHorizontalReachabilityEnabled_splitScreen_false() {
mAtm.mDevEnableNonResizableMultiWindow = true;
setUpDisplaySizeWithApp(2800, 1000);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
final TestSplitOrganizer organizer =
new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
@@ -3673,6 +3689,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(1000, 2800);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
final TestSplitOrganizer organizer =
new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
@@ -3694,6 +3711,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(1000, 2800);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
// Unresizable landscape-only activity.
prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_LANDSCAPE);
@@ -3715,6 +3733,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(/* dw */ 1000, /* dh */ 2800);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
@@ -3731,6 +3750,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(/* dw */ 2800, /* dh */ 1000);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
@@ -3747,6 +3767,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait display
setUpDisplaySizeWithApp(1400, 1600);
mActivity.mWmService.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
// 16:9f unresizable portrait app
prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
@@ -3760,6 +3781,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Landscape display
setUpDisplaySizeWithApp(1600, 1500);
mActivity.mWmService.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
// 16:9f unresizable landscape app
prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
@@ -3773,6 +3795,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(2800, 1000);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
// Unresizable portrait-only activity.
prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_PORTRAIT);
@@ -3794,6 +3817,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(1800, 2200);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
// Unresizable portrait-only activity.
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
@@ -3815,6 +3839,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(2200, 1800);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+ setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true);
// Unresizable landscape-only activity.
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
@@ -5011,6 +5036,14 @@ public class SizeCompatTests extends WindowTestsBase {
assertFalse(activity.shouldSendCompatFakeFocus());
}
+ private void setUpAllowThinLetterboxed(boolean thinLetterboxAllowed) {
+ spyOn(mActivity.mLetterboxUiController);
+ doReturn(thinLetterboxAllowed).when(mActivity.mLetterboxUiController)
+ .allowVerticalReachabilityForThinLetterbox();
+ doReturn(thinLetterboxAllowed).when(mActivity.mLetterboxUiController)
+ .allowHorizontalReachabilityForThinLetterbox();
+ }
+
private int getExpectedSplitSize(int dimensionToSplit) {
int dividerWindowWidth =
mActivity.mWmService.mContext.getResources().getDimensionPixelSize(
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 83e4151235ea..afa669807c2e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -487,6 +487,16 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Flush EVENT_APPEARED.
mController.dispatchPendingEvents();
+ // Even if the activity is not launched in an organized TaskFragment, it is still considered
+ // as the remote activity to the organizer process. Because when the task becomes visible,
+ // the organizer process needs to be interactive (unfrozen) to receive TaskFragment events.
+ activity.setVisibleRequested(true);
+ activity.setState(ActivityRecord.State.RESUMED, "test");
+ assertTrue(organizerProc.hasVisibleActivities());
+ activity.setVisibleRequested(false);
+ activity.setState(ActivityRecord.State.STOPPED, "test");
+ assertFalse(organizerProc.hasVisibleActivities());
+
// Make sure the activity belongs to the same app, but it is in a different pid.
activity.info.applicationInfo.uid = uid;
doReturn(pid + 1).when(activity).getPid();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 9d14290bdd8a..2e93cba80386 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -654,7 +654,10 @@ public class UsageStatsService extends SystemService implements
}
} else if (Intent.ACTION_USER_STARTED.equals(action)) {
if (userId >= 0) {
- mHandler.obtainMessage(MSG_USER_STARTED, userId, 0).sendToTarget();
+ if (!Flags.disableIdleCheck() || userId > 0) {
+ // Don't check idle state for USER_SYSTEM during the boot up.
+ mHandler.obtainMessage(MSG_USER_STARTED, userId, 0).sendToTarget();
+ }
}
}
}
@@ -2013,6 +2016,8 @@ public class UsageStatsService extends SystemService implements
+ ": " + Flags.useParceledList());
pw.println(" " + Flags.FLAG_FILTER_BASED_EVENT_QUERY_API
+ ": " + Flags.filterBasedEventQueryApi());
+ pw.println(" " + Flags.FLAG_DISABLE_IDLE_CHECK
+ + ": " + Flags.disableIdleCheck());
final int[] userIds;
synchronized (mLock) {
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index 40537c85784d..6d53c274cdf4 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -16,6 +16,8 @@
package com.android.server.usb;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import android.Manifest;
@@ -43,6 +45,7 @@ import android.os.AsyncTask;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.service.usb.UsbProfileGroupSettingsManagerProto;
import android.service.usb.UsbSettingsAccessoryPreferenceProto;
import android.service.usb.UsbSettingsDevicePreferenceProto;
@@ -939,13 +942,24 @@ public class UsbProfileGroupSettingsManager {
}
/**
- * @return true if any application in foreground have set restrict_usb_overlay_activities as
- * true in manifest file. The application needs to have MANAGE_USB permission.
+ * @return true if the user has not finished the setup process or if there are any
+ * foreground applications with MANAGE_USB permission and restrict_usb_overlay_activities
+ * enabled in the manifest file.
*/
private boolean shouldRestrictOverlayActivities() {
if (!Flags.allowRestrictionOfOverlayActivities()) return false;
+ if (Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ USER_SETUP_COMPLETE,
+ /* defaultValue= */ 1,
+ UserHandle.CURRENT.getIdentifier())
+ == 0) {
+ Slog.d(TAG, "restricting usb overlay activities as setup is not complete");
+ return true;
+ }
+
List<ActivityManager.RunningAppProcessInfo> appProcessInfos = mActivityManager
.getRunningAppProcesses();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4c719dd339e4..bc8f65edaa12 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3888,7 +3888,7 @@ public class CarrierConfigManager {
/**
* Whether device resets all of NR timers when device is in a voice call and QOS is established.
- * The default value is false;
+ * The default value is true;
*
* @see #KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING
* @see #KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING
@@ -10909,7 +10909,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "");
sDefaults.putInt(KEY_NR_ADVANCED_BANDS_SECONDARY_TIMER_SECONDS_INT, 0);
sDefaults.putBoolean(KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL, false);
- sDefaults.putBoolean(KEY_NR_TIMERS_RESET_ON_VOICE_QOS_BOOL, false);
+ sDefaults.putBoolean(KEY_NR_TIMERS_RESET_ON_VOICE_QOS_BOOL, true);
sDefaults.putBoolean(KEY_NR_TIMERS_RESET_ON_PLMN_CHANGE_BOOL, false);
/* Default value is 1 hour. */
sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index f161f319b0c2..0ecafc70b9a4 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1283,6 +1283,8 @@ public class PhoneNumberUtils {
private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+ private static final String SINGAPORE_ISO_COUNTRY_CODE = "SG";
+
/**
* Breaks the given number down and formats it according to the rules
* for the country the number is from.
@@ -1669,6 +1671,17 @@ public class PhoneNumberUtils {
* dialing format.
*/
result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
+ } else if (Flags.removeCountryCodeFromLocalSingaporeCalls() &&
+ (SINGAPORE_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
+ pn.getCountryCode() ==
+ util.getCountryCodeForRegion(SINGAPORE_ISO_COUNTRY_CODE) &&
+ (pn.getCountryCodeSource() ==
+ PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN))) {
+ /*
+ * Need to reformat Singaporean phone numbers (when the user is in Singapore)
+ * with the country code (+65) removed to comply with Singaporean regulations.
+ */
+ result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
} else {
result = util.formatInOriginalFormat(pn, defaultCountryIso);
}
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index f0bea3f3c28a..2909e66b53be 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -43,6 +43,9 @@ android_test {
"libmultiplejvmtiagentsinterferenceagent",
"libstaticjvmtiagent",
],
+ libs: [
+ "android.test.mock",
+ ],
certificate: "platform",
platform_apis: true,
test_suites: ["device-tests"],
diff --git a/tests/UsbManagerTests/src/com/android/server/usbtest/UsbProfileGroupSettingsManagerTest.java b/tests/UsbManagerTests/src/com/android/server/usbtest/UsbProfileGroupSettingsManagerTest.java
index 4780d8a610e8..87b26a63acc7 100644
--- a/tests/UsbManagerTests/src/com/android/server/usbtest/UsbProfileGroupSettingsManagerTest.java
+++ b/tests/UsbManagerTests/src/com/android/server/usbtest/UsbProfileGroupSettingsManagerTest.java
@@ -16,6 +16,8 @@
package com.android.server.usbtest;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+
import static com.android.server.usb.UsbProfileGroupSettingsManager.PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES;
import static org.mockito.ArgumentMatchers.any;
@@ -32,16 +34,20 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.Property;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbDevice;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
import androidx.test.runner.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.usb.UsbHandlerManager;
import com.android.server.usb.UsbProfileGroupSettingsManager;
import com.android.server.usb.UsbSettingsManager;
@@ -69,6 +75,7 @@ import java.util.List;
public class UsbProfileGroupSettingsManagerTest {
private static final String TEST_PACKAGE_NAME = "testPkg";
+
@Mock
private Context mContext;
@Mock
@@ -85,43 +92,78 @@ public class UsbProfileGroupSettingsManagerTest {
private UserManager mUserManager;
@Mock
private UsbUserSettingsManager mUsbUserSettingsManager;
- @Mock private Property mProperty;
- private ActivityManager.RunningAppProcessInfo mRunningAppProcessInfo;
- private PackageInfo mPackageInfo;
- private UsbProfileGroupSettingsManager mUsbProfileGroupSettingsManager;
+ @Mock
+ private Property mRestrictUsbOverlayActivitiesProperty;
+ @Mock
+ private UsbDevice mUsbDevice;
+
+ private MockContentResolver mContentResolver;
private MockitoSession mStaticMockSession;
+ private UsbProfileGroupSettingsManager mUsbProfileGroupSettingsManager;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mStaticMockSession = ExtendedMockito.mockitoSession()
+ .mockStatic(Flags.class)
+ .strictness(Strictness.WARN)
+ .startMocking();
- mRunningAppProcessInfo = new ActivityManager.RunningAppProcessInfo();
- mRunningAppProcessInfo.pkgList = new String[]{TEST_PACKAGE_NAME};
- mPackageInfo = new PackageInfo();
- mPackageInfo.packageName = TEST_PACKAGE_NAME;
- mPackageInfo.applicationInfo = Mockito.mock(ApplicationInfo.class);
+ when(mUsbSettingsManager.getSettingsForUser(anyInt())).thenReturn(mUsbUserSettingsManager);
+ when(mUserManager.getEnabledProfiles(anyInt()))
+ .thenReturn(List.of(Mockito.mock(UserInfo.class)));
+
+ mContentResolver = new MockContentResolver();
+ mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
when(mContext.getResources()).thenReturn(Mockito.mock(Resources.class));
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
when(mContext.createPackageContextAsUser(anyString(), anyInt(), any(UserHandle.class)))
.thenReturn(mContext);
- when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
- mUsbProfileGroupSettingsManager = new UsbProfileGroupSettingsManager(mContext, mUserHandle,
- mUsbSettingsManager, mUsbHandlerManager);
+ mUsbProfileGroupSettingsManager = new UsbProfileGroupSettingsManager(
+ mContext, mUserHandle, mUsbSettingsManager, mUsbHandlerManager);
- mStaticMockSession = ExtendedMockito.mockitoSession()
- .mockStatic(Flags.class)
- .strictness(Strictness.WARN)
- .startMocking();
+ setupDefaultConfiguration();
+ }
+ /**
+ * Setups the following configuration
+ *
+ * <ul>
+ * <li>Flag is enabled
+ * <li>Device setup has completed
+ * <li>There is a foreground activity with MANAGE_USB permission
+ * <li>The foreground activity has PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES enabled
+ * </ul>
+ */
+ private void setupDefaultConfiguration() throws NameNotFoundException {
+ when(Flags.allowRestrictionOfOverlayActivities()).thenReturn(true);
+
+ Settings.Secure.putInt(mContentResolver, USER_SETUP_COMPLETE, 1);
+
+ ActivityManager.RunningAppProcessInfo mRunningAppProcessInfo =
+ new ActivityManager.RunningAppProcessInfo();
+ mRunningAppProcessInfo.pkgList = new String[] { TEST_PACKAGE_NAME };
+ when(mActivityManager.getRunningAppProcesses()).thenReturn(List.of(mRunningAppProcessInfo));
+
+ PackageInfo mPackageInfo = new PackageInfo();
+ mPackageInfo.packageName = TEST_PACKAGE_NAME;
+ mPackageInfo.applicationInfo = Mockito.mock(ApplicationInfo.class);
when(mPackageManager.getPackageInfo(TEST_PACKAGE_NAME, 0)).thenReturn(mPackageInfo);
- when(mPackageManager.getProperty(eq(PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES),
- eq(TEST_PACKAGE_NAME))).thenReturn(mProperty);
- when(mUserManager.getEnabledProfiles(anyInt()))
- .thenReturn(List.of(Mockito.mock(UserInfo.class)));
- when(mUsbSettingsManager.getSettingsForUser(anyInt())).thenReturn(mUsbUserSettingsManager);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ new String[] { android.Manifest.permission.MANAGE_USB },
+ PackageManager.MATCH_SYSTEM_ONLY))
+ .thenReturn(List.of(mPackageInfo));
+
+ when(mRestrictUsbOverlayActivitiesProperty.getBoolean()).thenReturn(true);
+ when(mPackageManager.getProperty(
+ eq(PROPERTY_RESTRICT_USB_OVERLAY_ACTIVITIES), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(mRestrictUsbOverlayActivitiesProperty);
}
@After
@@ -130,66 +172,59 @@ public class UsbProfileGroupSettingsManagerTest {
}
@Test
- public void testDeviceAttached_flagTrueWithoutForegroundActivity_resolveActivityCalled() {
- when(Flags.allowRestrictionOfOverlayActivities()).thenReturn(true);
+ public void testDeviceAttached_foregroundActivityWithManifestField_resolveActivityNotCalled() {
+ mUsbProfileGroupSettingsManager.deviceAttached(mUsbDevice);
+
+ verify(mUsbUserSettingsManager, times(0)).queryIntentActivities(any(Intent.class));
+ }
+
+ @Test
+ public void testDeviceAttached_noForegroundActivity_resolveActivityCalled() {
when(mActivityManager.getRunningAppProcesses()).thenReturn(new ArrayList<>());
- when(mPackageManager.getPackagesHoldingPermissions(
- new String[]{android.Manifest.permission.MANAGE_USB},
- PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(List.of(mPackageInfo));
- UsbDevice device = Mockito.mock(UsbDevice.class);
- mUsbProfileGroupSettingsManager.deviceAttached(device);
+
+ mUsbProfileGroupSettingsManager.deviceAttached(mUsbDevice);
+
verify(mUsbUserSettingsManager).queryIntentActivities(any(Intent.class));
}
@Test
public void testDeviceAttached_noForegroundActivityWithUsbPermission_resolveActivityCalled() {
- when(Flags.allowRestrictionOfOverlayActivities()).thenReturn(true);
- when(mActivityManager.getRunningAppProcesses()).thenReturn(List.of(mRunningAppProcessInfo));
when(mPackageManager.getPackagesHoldingPermissions(
- new String[]{android.Manifest.permission.MANAGE_USB},
- PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(new ArrayList<>());
- UsbDevice device = Mockito.mock(UsbDevice.class);
- mUsbProfileGroupSettingsManager.deviceAttached(device);
+ new String[] { android.Manifest.permission.MANAGE_USB },
+ PackageManager.MATCH_SYSTEM_ONLY))
+ .thenReturn(new ArrayList<>());
+
+ mUsbProfileGroupSettingsManager.deviceAttached(mUsbDevice);
+
verify(mUsbUserSettingsManager).queryIntentActivities(any(Intent.class));
}
@Test
- public void testDeviceAttached_foregroundActivityWithManifestField_resolveActivityNotCalled() {
- when(Flags.allowRestrictionOfOverlayActivities()).thenReturn(true);
- when(mProperty.getBoolean()).thenReturn(true);
- when(mActivityManager.getRunningAppProcesses()).thenReturn(List.of(mRunningAppProcessInfo));
- when(mPackageManager.getPackagesHoldingPermissions(
- new String[]{android.Manifest.permission.MANAGE_USB},
- PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(List.of(mPackageInfo));
- UsbDevice device = Mockito.mock(UsbDevice.class);
- mUsbProfileGroupSettingsManager.deviceAttached(device);
- verify(mUsbUserSettingsManager, times(0))
- .queryIntentActivities(any(Intent.class));
- }
+ public void testDeviceAttached_restricUsbOverlayPropertyDisabled_resolveActivityCalled() {
+ when(mRestrictUsbOverlayActivitiesProperty.getBoolean()).thenReturn(false);
+
+ mUsbProfileGroupSettingsManager.deviceAttached(mUsbDevice);
- @Test
- public void testDeviceAttached_foregroundActivityWithoutManifestField_resolveActivityCalled() {
- when(Flags.allowRestrictionOfOverlayActivities()).thenReturn(true);
- when(mProperty.getBoolean()).thenReturn(false);
- when(mActivityManager.getRunningAppProcesses()).thenReturn(List.of(mRunningAppProcessInfo));
- when(mPackageManager.getPackagesHoldingPermissions(
- new String[]{android.Manifest.permission.MANAGE_USB},
- PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(List.of(mPackageInfo));
- UsbDevice device = Mockito.mock(UsbDevice.class);
- mUsbProfileGroupSettingsManager.deviceAttached(device);
verify(mUsbUserSettingsManager).queryIntentActivities(any(Intent.class));
}
@Test
- public void testDeviceAttached_flagFalseForegroundActivity_resolveActivityCalled() {
+ public void testDeviceAttached_flagFalse_resolveActivityCalled() {
when(Flags.allowRestrictionOfOverlayActivities()).thenReturn(false);
- when(mProperty.getBoolean()).thenReturn(true);
- when(mActivityManager.getRunningAppProcesses()).thenReturn(List.of(mRunningAppProcessInfo));
- when(mPackageManager.getPackagesHoldingPermissions(
- new String[]{android.Manifest.permission.MANAGE_USB},
- PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(List.of(mPackageInfo));
- UsbDevice device = Mockito.mock(UsbDevice.class);
- mUsbProfileGroupSettingsManager.deviceAttached(device);
+
+ mUsbProfileGroupSettingsManager.deviceAttached(mUsbDevice);
+
verify(mUsbUserSettingsManager).queryIntentActivities(any(Intent.class));
}
+
+ @Test
+ public void
+ testDeviceAttached_setupNotCompleteAndNoBlockingActivities_resolveActivityNotCalled() {
+ when(mRestrictUsbOverlayActivitiesProperty.getBoolean()).thenReturn(false);
+ Settings.Secure.putInt(mContentResolver, USER_SETUP_COMPLETE, 0);
+
+ mUsbProfileGroupSettingsManager.deviceAttached(mUsbDevice);
+
+ verify(mUsbUserSettingsManager, times(0)).queryIntentActivities(any(Intent.class));
+ }
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 960b57cb632a..580efe126ea3 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -70,6 +70,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.Uri;
+import android.net.vcn.Flags;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
@@ -82,7 +83,9 @@ import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -101,6 +104,7 @@ import com.android.server.vcn.util.PersistableBundleUtils;
import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -118,6 +122,8 @@ import java.util.UUID;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnManagementServiceTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final String CONTEXT_ATTRIBUTION_TAG = "VCN";
private static final String TEST_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName();
@@ -129,7 +135,12 @@ public class VcnManagementServiceTest {
private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2));
private static final VcnConfig TEST_VCN_CONFIG;
private static final VcnConfig TEST_VCN_CONFIG_PKG_2;
- private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
+
+ private static final int TEST_UID = 1010000; // A non-system user
+ private static final UserHandle TEST_USER_HANDLE = UserHandle.getUserHandleForUid(TEST_UID);
+ private static final UserHandle TEST_USER_HANDLE_OTHER =
+ UserHandle.of(TEST_USER_HANDLE.getIdentifier() + 1);
+
private static final String TEST_IFACE_NAME = "TEST_IFACE";
private static final String TEST_IFACE_NAME_2 = "TEST_IFACE2";
private static final LinkProperties TEST_LP_1 = new LinkProperties();
@@ -187,6 +198,7 @@ public class VcnManagementServiceTest {
private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
private final AppOpsManager mAppOpsMgr = mock(AppOpsManager.class);
+ private final UserManager mUserManager = mock(UserManager.class);
private final VcnContext mVcnContext = mock(VcnContext.class);
private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
mock(PersistableBundleUtils.LockingReadWriteHelper.class);
@@ -218,6 +230,9 @@ public class VcnManagementServiceTest {
Context.TELEPHONY_SUBSCRIPTION_SERVICE,
SubscriptionManager.class);
setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
+ setupSystemService(mMockContext, mUserManager, Context.USER_SERVICE, UserManager.class);
+
+ doReturn(TEST_USER_HANDLE).when(mUserManager).getMainUser();
doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
@@ -267,6 +282,8 @@ public class VcnManagementServiceTest {
@Before
public void setUp() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENFORCE_MAIN_USER);
+
doNothing()
.when(mMockContext)
.enforceCallingOrSelfPermission(
@@ -717,10 +734,8 @@ public class VcnManagementServiceTest {
}
@Test
- public void testSetVcnConfigRequiresSystemUser() throws Exception {
- doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
- .when(mMockDeps)
- .getBinderCallingUid();
+ public void testSetVcnConfigRequiresMainUser() throws Exception {
+ doReturn(TEST_USER_HANDLE_OTHER).when(mUserManager).getMainUser();
try {
mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
@@ -832,10 +847,8 @@ public class VcnManagementServiceTest {
}
@Test
- public void testClearVcnConfigRequiresSystemUser() throws Exception {
- doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
- .when(mMockDeps)
- .getBinderCallingUid();
+ public void testClearVcnConfigRequiresMainUser() throws Exception {
+ doReturn(TEST_USER_HANDLE_OTHER).when(mUserManager).getMainUser();
try {
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
@@ -921,10 +934,8 @@ public class VcnManagementServiceTest {
}
@Test
- public void testGetConfiguredSubscriptionGroupsRequiresSystemUser() throws Exception {
- doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
- .when(mMockDeps)
- .getBinderCallingUid();
+ public void testGetConfiguredSubscriptionGroupsRequiresMainUser() throws Exception {
+ doReturn(TEST_USER_HANDLE_OTHER).when(mUserManager).getMainUser();
try {
mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
index c8b60e5c335f..441a4ae6d9b6 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -20,6 +20,7 @@ import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS
import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY;
import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY;
+import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR;
import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.MIN_VALID_EXPECTED_RX_PACKET_NUM;
import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.getMaxSeqNumIncreasePerSecond;
import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
@@ -584,4 +585,56 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED,
getMaxSeqNumIncreasePerSecond(mCarrierConfig));
}
+
+ private IpSecPacketLossDetector newDetectorAndSetTransform(int threshold) throws Exception {
+ when(mCarrierConfig.getInt(
+ eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY),
+ anyInt()))
+ .thenReturn(threshold);
+
+ final IpSecPacketLossDetector detector =
+ new IpSecPacketLossDetector(
+ mVcnContext,
+ mNetwork,
+ mCarrierConfig,
+ mMetricMonitorCallback,
+ mDependencies);
+
+ detector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */);
+ detector.setInboundTransformInternal(mIpSecTransform);
+
+ return detector;
+ }
+
+ @Test
+ public void testDisableAndEnableDetectorWithCarrierConfig() throws Exception {
+ final IpSecPacketLossDetector detector =
+ newDetectorAndSetTransform(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR);
+
+ assertFalse(detector.isStarted());
+
+ when(mCarrierConfig.getInt(
+ eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY),
+ anyInt()))
+ .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD);
+ detector.setCarrierConfig(mCarrierConfig);
+
+ assertTrue(detector.isStarted());
+ }
+
+ @Test
+ public void testEnableAndDisableDetectorWithCarrierConfig() throws Exception {
+ final IpSecPacketLossDetector detector =
+ newDetectorAndSetTransform(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD);
+
+ assertTrue(detector.isStarted());
+
+ when(mCarrierConfig.getInt(
+ eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY),
+ anyInt()))
+ .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR);
+ detector.setCarrierConfig(mCarrierConfig);
+
+ assertFalse(detector.isStarted());
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
index edad67896e8e..0439d5f54e23 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -123,6 +123,7 @@ public abstract class NetworkEvaluationTestBase {
mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS);
mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE);
mSetFlagsRule.enableFlags(Flags.FLAG_HANDLE_SEQ_NUM_LEAP);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_DISABLE_IPSEC_LOSS_DETECTOR);
when(mNetwork.getNetId()).thenReturn(-1);
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index f1e4ead03314..669cddb9af5a 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -443,7 +443,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagn
manifest_action.Action(AutoGenerateIsSplitRequired);
manifest_action.Action(VerifyManifest);
manifest_action.Action(FixCoreAppAttribute);
- manifest_action.Action([&](xml::Element* el) -> bool {
+ manifest_action.Action([this, diag](xml::Element* el) -> bool {
EnsureNamespaceIsDeclared("android", xml::kSchemaAndroid, &el->namespace_decls);
if (options_.version_name_default) {
@@ -506,7 +506,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagn
manifest_action["eat-comment"];
// Uses-sdk actions.
- manifest_action["uses-sdk"].Action([&](xml::Element* el) -> bool {
+ manifest_action["uses-sdk"].Action([this](xml::Element* el) -> bool {
if (options_.min_sdk_version_default &&
el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion") == nullptr) {
// There was no minSdkVersion defined and we have a default to assign.
@@ -528,7 +528,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagn
// Instrumentation actions.
manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
- manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
+ manifest_action["instrumentation"].Action([this](xml::Element* el) -> bool {
if (!options_.rename_instrumentation_target_package) {
return true;
}
@@ -544,7 +544,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagn
manifest_action["attribution"];
manifest_action["attribution"]["inherit-from"];
manifest_action["original-package"];
- manifest_action["overlay"].Action([&](xml::Element* el) -> bool {
+ manifest_action["overlay"].Action([this](xml::Element* el) -> bool {
if (options_.rename_overlay_target_package) {
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) {
attr->value = options_.rename_overlay_target_package.value();
@@ -625,7 +625,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagn
uses_package_action["additional-certificate"];
if (options_.debug_mode) {
- application_action.Action([&](xml::Element* el) -> bool {
+ application_action.Action([](xml::Element* el) -> bool {
xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable");
attr->value = "true";
return true;
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
index 5659a35170c1..2e144f5513bc 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
@@ -15,11 +15,11 @@
*/
package com.android.hoststubgen.filters
-import com.android.hoststubgen.UnknownApiException
import com.android.hoststubgen.addNonNullElement
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.toHumanReadableClassName
import com.android.hoststubgen.asm.toHumanReadableMethodName
+import com.android.hoststubgen.log
// TODO: Validate all input names.
@@ -48,30 +48,30 @@ class InMemoryOutputFilter(
return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className)
}
- private fun ensureClassExists(className: String) {
+ private fun checkClass(className: String) {
if (classes.findClass(className) == null) {
- throw UnknownApiException("Unknown class $className")
+ log.w("Unknown class $className")
}
}
- private fun ensureFieldExists(className: String, fieldName: String) {
+ private fun checkField(className: String, fieldName: String) {
if (classes.findField(className, fieldName) == null) {
- throw UnknownApiException("Unknown field $className.$fieldName")
+ log.w("Unknown field $className.$fieldName")
}
}
- private fun ensureMethodExists(
+ private fun checkMethod(
className: String,
methodName: String,
descriptor: String
) {
if (classes.findMethod(className, methodName, descriptor) == null) {
- throw UnknownApiException("Unknown method $className.$methodName$descriptor")
+ log.w("Unknown method $className.$methodName$descriptor")
}
}
fun setPolicyForClass(className: String, policy: FilterPolicyWithReason) {
- ensureClassExists(className)
+ checkClass(className)
mPolicies[getClassKey(className)] = policy
}
@@ -81,7 +81,7 @@ class InMemoryOutputFilter(
}
fun setPolicyForField(className: String, fieldName: String, policy: FilterPolicyWithReason) {
- ensureFieldExists(className, fieldName)
+ checkField(className, fieldName)
mPolicies[getFieldKey(className, fieldName)] = policy
}
@@ -100,7 +100,7 @@ class InMemoryOutputFilter(
descriptor: String,
policy: FilterPolicyWithReason,
) {
- ensureMethodExists(className, methodName, descriptor)
+ checkMethod(className, methodName, descriptor)
mPolicies[getMethodKey(className, methodName, descriptor)] = policy
}
@@ -110,8 +110,8 @@ class InMemoryOutputFilter(
}
fun setRenameTo(className: String, methodName: String, descriptor: String, toName: String) {
- ensureMethodExists(className, methodName, descriptor)
- ensureMethodExists(className, toName, descriptor)
+ checkMethod(className, methodName, descriptor)
+ checkMethod(className, toName, descriptor)
mRenames[getMethodKey(className, methodName, descriptor)] = toName
}
@@ -121,7 +121,7 @@ class InMemoryOutputFilter(
}
fun setNativeSubstitutionClass(from: String, to: String) {
- ensureClassExists(from)
+ checkClass(from)
// Native substitute classes may be provided from other jars, so we can't do this check.
// ensureClassExists(to)
diff --git a/wifi/wifi.aconfig b/wifi/wifi.aconfig
index 3c734bc7e1e3..c5bc0396de34 100644
--- a/wifi/wifi.aconfig
+++ b/wifi/wifi.aconfig
@@ -9,3 +9,11 @@ flag {
bug: "313038031"
is_fixed_read_only: true
}
+
+flag {
+ name: "network_provider_battery_charging_status"
+ is_exported: true
+ namespace: "wifi"
+ description: "Control the API that allows setting / reading the NetworkProviderInfo's battery charging status"
+ bug: "305067231"
+}